MIN y MAX en C


301

¿Dónde están MINy se MAXdefinen en C, en todo caso?

¿Cuál es la mejor manera de implementarlos de la forma más genérica posible? (Se prefieren las extensiones / compiladores del compilador para compiladores convencionales).

Respuestas:


392

¿Dónde están MINy se MAXdefinen en C, en todo caso?

No lo son

¿Cuál es la mejor manera de implementarlos de la forma más genérica y segura posible? (Se prefieren las extensiones / compilaciones de compiladores para compiladores convencionales).

Como funciones. No usaría macros como #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), especialmente si planea implementar su código. Escriba el suyo, use algo como estándar fmaxo fmin, o arregle la macro usando el tipo de GCC (también obtiene un bono de seguridad de tipo) en una expresión de declaración de GCC :

 #define max(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a > _b ? _a : _b; })

Todo el mundo dice "oh, sé acerca de la doble evaluación, no hay problema" y en unos meses más adelante, estarás depurando los problemas más tontos durante horas y horas.

Tenga en cuenta el uso de en __typeof__lugar de typeof:

Si está escribiendo un archivo de encabezado que debe funcionar cuando se incluye en los programas ISO C, escriba en __typeof__lugar de typeof.


68
Sabes, sería bastante útil si gcc tuviera una advertencia en la línea de: warning: expression with side-effects multiply evaluated by macroen el punto de uso ...
caf

23
@caf: ¿no requeriría eso que el preprocesador tenga un conocimiento más complicado de la sintaxis de C?
dreamlax

3
Después de mucho tratar de averiguarlo, no creo que haya de todos modos hacer esto en VC ++, pero lo mejor es tratar de meterse con la nueva decltypepalabra clave MSVC ++ 2010 , pero aun así, Visual Studio no puede hacer declaraciones compuestas en macros (y decltypees C ++ de todos modos), es decir, la ({ ... })sintaxis de GCC, así que estoy bastante seguro de que, de todos modos, no es posible. No he mirado ningún otro compilador con respecto a este tema, lo siento Luther: S
David Titarenco

77
@dreamlax Una vez vi un caso en el que alguien había hecho MAX(someUpperBound, someRandomFunction())para limitar un valor aleatorio a un límite superior. Fue una idea terrible, pero tampoco funcionó, porque el MAXque estaba usando tenía el doble problema de evaluación, por lo que terminó con un número aleatorio diferente al que se evaluó inicialmente.
Zev Eisenberg

8
@Soumen Por ejemplo, si llama MIN(x++, y++)al preprocesador generará el siguiente código (((x++) < (y++)) ? (x++) : (y++)). Entonces, xy yse incrementará dos veces.
Antonio

91

También se proporciona en las versiones GNU libc (Linux) y FreeBSD de sys / param.h, y tiene la definición proporcionada por dreamlax.


En Debian:

$ uname -sr
Linux 2.6.11

$ cat /etc/debian_version
5.0.2

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

$ head -n 2 /usr/include/sys/param.h | grep GNU
This file is part of the GNU C Library.

En FreeBSD:

$ uname -sr
FreeBSD 5.5-STABLE

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

Los repositorios de origen están aquí:


He agregado las definiciones de los sistemas a los que tengo acceso en mi respuesta anterior (el campo de comentarios no acepta el formato por lo que puedo decir). Intentará encontrar los enlaces a los repositorios de código fuente de FreeBSD / Linux / glibc.
Mikel

+1. Muy agradable. Funciona para openSUSE/Linux 3.1.0-1.2-desktop/ gcc version 4.6.2 (SUSE Linux) también. :) Malo, no es portátil.
Jack

Funciona también en Cygwin.
CMCDragonkai

1
Espera un momento. No impide la doble evaluación, ¿verdad? : 3
usuario1857492

76

Hay un std::miny std::maxen C ++, pero AFAIK, no hay equivalente en la biblioteca estándar de C. Puede definirlos usted mismo con macros como

#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))

Pero esto causa problemas si escribes algo así MAX(++a, ++b).


10
¿Por qué poner demasiados corchetes? Encontré un cuestionario donde dijeron #define MIN(A, B) ((A < B) ? A : B)que no es una forma flexible, ¿por qué?

79
@Makouda: los paréntesis adicionales en las macros ayudan a evitar problemas de precedencia de operadores. Por ejemplo, considere #define MULT(x, y) x * y. Luego se MULT(a + b, a + b)expande a a + b * a + b, que analiza como a + (b * a) + bdebido a la precedencia. Eso no es lo que el programador probablemente pretendía.
dan04

que no es necesario cuando: tiene la prioridad más baja de todos modos?
Alero Sendón

1
@WingerSendon: no lo hace; el operador de coma lo hace.
dan04

24

Evite las extensiones de compilador no estándar e impleméntelo como una macro completamente segura de tipo en estándar C puro (ISO 9899: 2011).

Solución

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

Uso

MAX(int, 2, 3)

Explicación

La macro MAX crea otra macro basada en el typeparámetro. Esta macro de control, si se implementa para el tipo dado, se usa para verificar que ambos parámetros sean del tipo correcto. Si typeno se admite, habrá un error del compilador.

Si x o y no son del tipo correcto, habrá un error de compilación en las ENSURE_macros. Se pueden agregar más macros de este tipo si se admiten más tipos. Supuse que solo se usarán tipos aritméticos (enteros, flotantes, punteros, etc.) y no estructuras o matrices, etc.

Si todos los tipos son correctos, se llamará a la macro GENERIC_MAX. Se necesitan paréntesis adicionales alrededor de cada parámetro macro, como la precaución estándar habitual al escribir macros C.

Luego están los problemas habituales con las promociones de tipo implícito en C. El ?:operador equilibra el segundo y el tercer operando entre sí. Por ejemplo, el resultado de GENERIC_MAX(my_char1, my_char2)sería un int. Para evitar que la macro realice tales promociones de tipo potencialmente peligrosas, se utilizó una conversión de tipo final al tipo deseado.

Razón fundamental

Queremos que ambos parámetros de la macro sean del mismo tipo. Si uno de ellos es de un tipo diferente, la macro ya no es segura, ya que un operador similar ?:generará promociones de tipo implícito. Y debido a que lo hace, también siempre necesitamos devolver el resultado final al tipo deseado como se explicó anteriormente.

Una macro con un solo parámetro podría haberse escrito de una manera mucho más simple. Pero con 2 o más parámetros, es necesario incluir un parámetro de tipo adicional. Porque algo como esto es lamentablemente imposible:

// this won't work
#define MAX(x, y)                                  \
  _Generic((x),                                    \
           int: GENERIC_MAX(x, ENSURE_int(y))      \
           float: GENERIC_MAX(x, ENSURE_float(y))  \
          )

El problema es que si la macro anterior se llama como MAX(1, 2)con dos int, aún intentará expandir macro todos los escenarios posibles de la _Genericlista de asociación. Por lo tanto, la ENSURE_floatmacro también se expandirá, aunque no sea relevante para int. Y dado que esa macro intencionalmente solo contiene el floattipo, el código no se compilará.

Para resolver esto, creé el nombre de la macro durante la fase de preprocesador, con el operador ##, para que ninguna macro se expanda accidentalmente.

Ejemplos

#include <stdio.h>

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

int main (void)
{
  int    ia = 1,    ib = 2;
  float  fa = 3.0f, fb = 4.0f;
  double da = 5.0,  db = 6.0;

  printf("%d\n", MAX(int,   ia, ib)); // ok
  printf("%f\n", MAX(float, fa, fb)); // ok

//printf("%d\n", MAX(int,   ia, fa));  compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib));  compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db));  compiler error, one of the types is wrong

//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
  return 0;
}

Por GENERIC_MAXcierto, esa macro es una mala idea, solo tiene que intentar GENERIC_MAX(var++, 7)averiguar por qué :-) Hoy en día (especialmente con compiladores altamente optimizados / en línea), las macros deberían relegarse solo a los formularios simples. Las funciones similares son mejores como funciones y las de grupo de valores mejores como enumeraciones.
paxdiablo

21

No creo que sean macros estandarizadas. Ya hay funciones estandarizadas para coma flotante fmaxy fmin(y fmaxfpara flotantes y fmaxlpara dobles largos).

Puede implementarlos como macros siempre que conozca los problemas de los efectos secundarios / doble evaluación.

#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)

En la mayoría de los casos, puede dejarlo al compilador para determinar lo que está tratando de hacer y optimizarlo lo mejor que pueda. Si bien esto causa problemas cuando se usa como MAX(i++, j++), dudo que haya mucha necesidad de verificar el máximo de valores incrementales de una sola vez. Incremente primero, luego verifique.


Esta debería ser la respuesta preferida ya que claramente hay funciones mínimas
imranal

@imranal ¿De qué estás hablando exactamente? ¿El código de implementación de esas bibliotecas? Pero ese código no está expuesto , es decir, no lo están colocando en la interfaz de la biblioteca, siendo potencialmente inseguro.
Antonio

@ Antonio Creo que está utilizando definiciones incorrectas de "expuesto" e "interfaz". La interfaz de la biblioteca ac son las variables externas, los tipos, las macros y las declaraciones de funciones en un archivo de encabezado; fmin / fmax se declaran en el archivo de encabezado, por lo que se dice que están expuestos. Sin embargo, no estoy seguro de a qué se refiere como inseguro.
racionalcoder

21

Esta es una respuesta tardía, debido a un desarrollo bastante reciente. Dado que el OP aceptó la respuesta que se basa en una extensión GCC (y clang) no portátil typeof, o __typeof__para ISO C 'limpia', hay una mejor solución disponible a partir de gcc-4.9 .

#define max(x,y) ( \
    { __auto_type __x = (x); __auto_type __y = (y); \
      __x > __y ? __x : __y; })

El beneficio obvio de esta extensión es que cada argumento macro solo se expande una vez, a diferencia de la __typeof__solución.

__auto_typees una forma limitada de C ++ 11's auto. No puede (¿o no debería?) Usarse en código C ++, aunque no hay una buena razón para no usar las capacidades superiores de inferencia de tipos autocuando se usa C ++ 11.

Dicho esto, supongo que no hay problemas al usar esta sintaxis cuando la macro se incluye en un extern "C" { ... }ámbito; por ejemplo, de un encabezado C. AFAIK, esta extensión no ha encontrado su camino información clang


Relacionado con el comentario de Brett Hale , clangcomenzó a respaldar __auto_typealrededor de 2016 (ver parche ).
Lars

Felicitaciones por el reconocimiento del problema macro, pero todavía me postular que una función probablemente sería mejor :-)
paxdiablo

@paxdiablo: estoy de acuerdo, aunque la pregunta tiene la c-preprocessoretiqueta. No se garantiza que una función esté en línea incluso con dicha palabra clave, a menos que se utilice algo como el __always_inline__atributo de gcc .
Brett Hale

11

Escribí esta versión que funciona para MSVC, GCC, C y C ++.

#if defined(__cplusplus) && !defined(__GNUC__)
#   include <algorithm>
#   define MIN std::min
#   define MAX std::max
//#   define TMIN(T, a, b) std::min<T>(a, b)
//#   define TMAX(T, a, b) std::max<T>(a, b)
#else
#       define _CHOOSE2(binoper, lexpr, lvar, rexpr, rvar) \
                ({ \
                        decltype(lexpr) lvar = (lexpr); \
                        decltype(rexpr) rvar = (rexpr); \
                        lvar binoper rvar ? lvar : rvar; \
                })
#       define _CHOOSE_VAR2(prefix, unique) prefix##unique
#       define _CHOOSE_VAR(prefix, unique) _CHOOSE_VAR2(prefix, unique)
#       define _CHOOSE(binoper, lexpr, rexpr) \
                _CHOOSE2( \
                        binoper, \
                        lexpr, _CHOOSE_VAR(_left, __COUNTER__), \
                        rexpr, _CHOOSE_VAR(_right, __COUNTER__) \
                )
#       define MIN(a, b) _CHOOSE(<, a, b)
#       define MAX(a, b) _CHOOSE(>, a, b)
#endif

1
He votado a favor, pero los identificadores que comienzan con un guión bajo seguido de una letra mayúscula están reservados.
dreamlax

8

Si necesita min / max para evitar una rama costosa, no debe usar el operador ternario, ya que se compilará en un salto. El siguiente enlace describe un método útil para implementar una función min / max sin ramificación.

http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax


1
Si el compilador es lo suficientemente inteligente, puede evitar la rama
Axel Gneiting

2
Si la optimización está activada, todos los compiladores modernos emitirán un movimiento condicional en lugar de una rama en la mayoría de los casos, por lo que no tiene mucho sentido usar hacks como este.
Krzysztof Kosiński

2
Absolutamente cierto, no tengo idea de lo que estaba mirando en ese entonces, ha pasado un tiempo. Tanto gcc como clang evitan las ramas con -O, tanto en x86 como en armv7a.
cib

6

@David Titarenco lo clavó aquí , pero permítame al menos limpiarlo un poco para que se vea bien, y mostrar ambosmin() y max() juntos para que sea más fácil copiar y pegar desde aquí. :)

Actualización 25 de abril de 2020: también agregué una Sección 3 para mostrar cómo se haría esto también con las plantillas de C ++, como una valiosa comparación para aquellos que aprenden C y C ++, o que hacen la transición de una a otra. He hecho todo lo posible para ser minucioso, objetivo y correcto para hacer de esta respuesta una referencia canónica a la que pueda volver una y otra vez, y espero que lo encuentres tan útil como yo.

1. La antigua forma macro C:

Esta técnica es de uso común, muy respetada por aquellos que saben cómo usarla adecuadamente, la forma "de facto" de hacer las cosas, y está bien si se usa correctamente, pero con errores (piense: efecto secundario de doble evaluación ) si alguna vez pasa expresiones que incluyen asignación de variables para comparar:

#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))

2. El nuevo y mejorado gcc " expresión de declaración :

Esta técnica evita los efectos secundarios y los errores anteriores de "doble evaluación" y, por lo tanto, se considera superior, más seguro y "más moderno". forma GCC C de hacerlo. Espere que funcione con los compiladores gcc y clang, ya que clang es, por diseño, compatible con gcc (vea la nota de clang al final de esta respuesta).

PERO: ¡Tenga cuidado con los efectos de " sombreado variable " todavía, ya que las expresiones de declaración aparentemente están en línea y, por lo tanto, NO tienen su propio alcance de variable local!

#define max(a,b)             \
({                           \
    __typeof__ (a) _a = (a); \
    __typeof__ (b) _b = (b); \
    _a > _b ? _a : _b;       \
})

#define min(a,b)             \
({                           \
    __typeof__ (a) _a = (a); \
    __typeof__ (b) _b = (b); \
    _a < _b ? _a : _b;       \
})

Tenga en cuenta que en las expresiones de instrucción gcc, la última expresión en el bloque de código es lo que se "devuelve" de la expresión, como si se devolviera de una función. La documentación de GCC lo dice de esta manera:

Lo último en la declaración compuesta debe ser una expresión seguida de un punto y coma; El valor de esta subexpresión sirve como el valor de toda la construcción. (Si usa algún otro tipo de enunciado último dentro de las llaves, la construcción tiene un tipo nulo y, por lo tanto, efectivamente no tiene valor).

3. La forma de la plantilla C ++:

Nota de C ++: si usa C ++, probablemente se recomiendan plantillas para este tipo de construcción, pero personalmente no me gustan las plantillas y probablemente usaría una de las construcciones anteriores en C ++ de todos modos, ya que frecuentemente uso y prefiero los estilos C en C ++ incrustado también.

Esta sección agregó 25 de abril de 2020:

He estado haciendo un montón de C ++ en los últimos meses, y la presión para preferir plantillas en lugar de macros, donde sea posible, en la comunidad de C ++ es bastante fuerte. Como resultado, he mejorado en el uso de plantillas, y quiero incluir aquí las versiones de plantilla de C ++ para completar y hacer de esto una respuesta más canónica y exhaustiva.

A continuación, se muestran las versiones básicas de la plantilla de funcionesmax() y min()cómo se verían en C ++:

template <typename T>
T max(T a, T b)
{
    return a > b ? a : b;
}

template <typename T>
T min(T a, T b)
{
    return a < b ? a : b;
}

Lea más sobre las plantillas de C ++ aquí: Wikipedia: Plantilla (C ++) .

Sin embargo, ambos max()y min()ya forman parte de la biblioteca estándar de C ++, en el <algorithm>encabezado ( #include <algorithm>). En la biblioteca estándar de C ++ se definen de forma ligeramente diferente a la que tengo arriba. Los prototipos predeterminados para std::max<>()y std::min<>(), por ejemplo, en C ++ 14, mirando sus prototipos en los enlaces de cplusplus.com justo arriba, son:

template <class T> 
constexpr const T& max(const T& a, const T& b);

template <class T> 
constexpr const T& min(const T& a, const T& b);

Tenga en cuenta que la palabra clave typenamees un alias para class(por lo que su uso es idéntico si usted dice <typename T>o <class T>), ya que más tarde se reconoció después de la invención de las plantillas C ++, que el tipo de plantilla podría ser un tipo regular ( int,float , etc.) en lugar de solamente Un tipo de clase.

Aquí puede ver que ambos tipos de entrada, así como el tipo de retorno, son const T&, lo que significa "referencia constante al tipo T". Esto significa que los parámetros de entrada y el valor de retorno se pasan por referencia en lugar de pasar por valor . Esto es como pasar por punteros y es más eficiente para tipos grandes, como los objetos de clase. La constexprparte de la función modifica la función en sí misma e indica que la función debe poder evaluarse en tiempo de compilación (al menos si se proporcionan constexprparámetros de entrada), pero si no se puede evaluar en tiempo de compilación, vuelve a un valor predeterminado evaluación en tiempo de ejecución, como cualquier otra función normal.

El aspecto en tiempo de compilación de una constexprfunción C ++ hace que sea una especie de macro de C, ya que si la evaluación en tiempo de compilación es posible para una constexprfunción, se realizará en tiempo de compilación, igual que una MIN()oMAX() podría posiblemente la sustitución de macros ser evaluado completamente en tiempo de compilación en C o C ++ también. Para obtener referencias adicionales para esta información de plantilla de C ++, consulte a continuación.

Referencias

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. MIN y MAX en C
  4. Se agregaron referencias adicionales de plantillas de C ++ en abril de 2020:
    1. ***** Wikipedia: Plantilla (C ++) <- ¡GRAN información adicional sobre las plantillas de C ++!
    2. (Mi propia pregunta y respuesta): ¿Por qué es `constexpr` parte del prototipo de plantilla C ++ 14 para` std :: max () `?
    3. Diferencia entre `constexpr` y` const`

Nota de Clang de Wikipedia :

[Clang] está diseñado para actuar como un reemplazo directo de GNU Compiler Collection (GCC), y admite la mayoría de sus indicadores de compilación y extensiones de lenguaje no oficiales.


Para el votante negativo de las últimas 24 horas: ¡buenas noticias! Eliminé mi discurso de la Sección 4 que agregué ayer con la Sección 3, y lo puse aquí en su lugar . Puede reevaluar mi respuesta y darle un voto positivo si lo desea, ya que he puesto mucha buena información y he hecho todo lo posible para que sea una respuesta canónica sólida, útil y beneficiosa para todos. Ahora ha vuelto a estar enfocado. :) ¡Gracias!
Gabriel Staples

4

Vale la pena señalar que creo que si define miny maxcon el terciario como

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

luego para obtener el mismo resultado para el caso especial de fmin(-0.0,0.0)y fmax(-0.0,0.0)necesita intercambiar los argumentos

fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)

Todavía no funcionará para NaN. fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
greggo

@greggo, di una mejor respuesta aquí stackoverflow.com/a/30915238/2542702
Z boson

4

Parece que Windef.h(a la #include <windows.h>) tiene maxy min(minúsculas) macros, que también sufren la dificultad de "doble evaluación", pero están ahí para aquellos que no quieren volver a rodar las suyas :)


12
¿Estás incluso sorprendido?
Matt Joiner

2

Sé que el tipo dijo "C" ... Pero si tienes la oportunidad, usa una plantilla de C ++:

template<class T> T min(T a, T b) { return a < b ? a : b; }

Escriba safe, y no hay problemas con el ++ mencionado en otros comentarios.


16
Los argumentos deben ser referencias constantes, nunca se sabe qué usuario pasará.
nmikhailov

66
Dicha función ya ha sido estandarizada ( std :: min ).
dreamlax

C ++ tiene muchas funciones estándar para la mayoría de los propósitos normales, no reinventes la rueda. Sin embargo, MS también define su propio mínimo / máximo, lo que a veces causa problemas
phuclv

0

El máximo de dos enteros ay bes (int)(0.5((a+b)+abs(a-b))). Esto también puede funcionar con (double)y fabs(a-b)para dobles (similar para flotadores)


Lo siento si esto está mal, soy un principiante en C pero este código funciona para mí
NRZ

2
No estoy seguro de que funcione con no enteros. La matemática de punto flotante tiene una precisión no lineal.
Treesrule14

Para ampliar el comentario de @ Treesrule14: Esto no funciona porque las computadoras no tratan los números de la misma manera que los matemáticos. El punto flotante tiene problemas de redondeo, por lo que es poco probable que obtenga la respuesta correcta. Incluso si usa matemáticas enteras, MAX_INT + MAX_INT da -2, por lo que max (MAX_INT, MAX_INT) usando su fórmula saldría como -1.
user9876

-3

La forma más simple es definirlo como una función global en un .harchivo y llamarlo cuando lo desee, si su programa es modular con muchos archivos. Si no, double MIN(a,b){return (a<b?a:b)}es la forma más sencilla.


1
@technosaurus Sería útil si describiera por qué esta solución es incorrecta, no solo que lo es.
Tur1ng

@technosaurus, su respuesta es realmente inútil. Tur1ing, parece que la función se define completamente incorrecta (faltan tipos en los parámetros de entrada, falta el punto y coma después de la declaración de retorno), y la conversión de entradas int a double es una mala manera de hacer las cosas, por lo que el tipo no debe ser doble. Una expresión de definición o declaración sería mejor aquí (por ejemplo: ver aquí ), pero si es una función, considere hacer una función para hacer esto para los tipos int32_t, una para los tipos uint32_t y otra para los tipos flotante o doble, para un total de 3 diferentes funciones
Gabriel Staples

1
@GabrielStaples Esta respuesta debe marcarse como no una respuesta, no hay ayuda. Aunque podría usarse como un ejemplo de cómo ser el más equivocado en la menor cantidad de espacio. Recomendar funciones globales en un encabezado (¿no está en línea estática incluso?) Romperá el código con más de 2 unidades de compilación, ni siquiera compila, nombra una función como una macro, entradas implícitas como su 1989, devuelve un doble sin razón explícita, implícita lanzamientos que causarán advertencias en el mejor de los casos ... y lo más importante, NO RESPONDE LA PREGUNTA: no es genérico, no es seguro para el tipo y definitivamente no es la mejor manera
technosaurus

Cada uno de esos problemas merece más críticas que no se pueden cubrir con suficiente detalle.
technosaurus
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.