Obtener el valor máximo de una variable en C

¿Hay una función en C que devuelva el valor máximo de una variable como esta (nombraré la función “valor máximo” en el ejemplo a continuación)?

int a; printf("%d", maxvalue(a)); // 32767 unsigned int b; printf("%d", maxvalue(b)); // 65535 

Básicamente, la función devuelve valores como INT_MAX cuando la variable está firmada INT, UINT_MAX cuando no está firmada int, etc.

Dicha función no está definida por la biblioteca estándar de C. Puedes intentar definir una macro que la calcule:

 #define MAX_VALUE(a) (((unsigned long long)1 << (sizeof(a) * CHAR_BIT)) - 1) 

Al usarlo, tenga cuidado ya que está asignado a un tipo lo suficientemente grande. Por ejemplo:

 #include  #include  #include  #define IS_TYPE_SIGNED(a) ((a-1) < 0) #define MAX_VALUE_UNSIGNED(a) (((unsigned long long)1 << \ (sizeof(a) * CHAR_BIT)) - 1) #define MAX_VALUE_SIGNED(a) (MAX_VALUE_UNSIGNED(a) >> 1) #define MAX_VALUE(a) (IS_TYPE_SIGNED(a) ? \ MAX_VALUE_SIGNED(a) : MAX_VALUE_UNSIGNED(a)) int main(void) { unsigned int i = 0; signed int j = 0; printf("%llu\n", MAX_VALUE(i)); printf("%llu\n", MAX_VALUE(j)); return EXIT_SUCCESS; } 

Esto imprime:

 4294967295 2147483647 

Puede hacerlo con bastante facilidad con una expresión genérica de tipo C11 :

 #define maxvalue(type) _Generic(type, int: INT_MAX, \ unsigned int: UINT_MAX) 

No es una función, pero creo que hace lo que quieres. Aquí hay un progtwig de ejemplo simple:

 #include  #include  #define maxvalue(type) _Generic(type, int: INT_MAX, \ unsigned int: UINT_MAX) int main(void) { int i; unsigned int ui; printf("%u\n", maxvalue(i)); printf("%u\n", maxvalue(ui)); return 0; } 

Y su salida:

 $ clang -Wall -Werror -Wextra -pedantic -std=c11 example.c -o example $ ./example 2147483647 4294967295 

Mis respuestas son más amplias que las suyas porque mi sistema tiene enteros de 32 bits. Parece que tienes una máquina de 16 bits.

Aquí hay macros de mi biblioteca que funcionan para tipos, en lugar de variables:

 /* min and max integer values. T is a signed or unsigned integer type. */ /* Returns 1 if T is signed, else 0. */ #define INTTYPE_SIGNED(T) ((T)-1 < (T)0) /* * Returns (T)(maximum value of a T). * * Pains are taken (perhaps unnecessarily) to avoid integer overflow * with signed types. */ #define INTTYPE_MAX(T) \ (((T)1 << (CHAR_BIT*sizeof(T)-INTTYPE_SIGNED(T)-1)) - 1 + \ ((T)1 << (CHAR_BIT*sizeof(T)-INTTYPE_SIGNED(T)-1))) /* * Returns (T)(minimum value of a T). * Pains are taken (perhaps unnecessarily) to avoid integer overflow * with signed types. * assert: twos complement architecture */ #define INTTYPE_MIN(T) ((T)(-INTTYPE_MAX(T)-1)) 

Edición: Adaptándolos a la pregunta:

 /* min and max integer values. V is a signed or unsigned integer value. */ /* Returns 1 if V has signed type, else 0. */ #define INT_VALUE_SIGNED(V) ((V)-(V)-1 < 0) /* * Returns maximum value for V's type. * * Pains are taken (perhaps unnecessarily) to avoid integer overflow * with signed types. */ #define INT_VALUE_MAX(V) \ (((V)-(V)+1 << (CHAR_BIT*sizeof(V)-INT_VALUE_SIGNED(V)-1)) - 1 + \ ((V)-(V)+1 << (CHAR_BIT*sizeof(V)-INT_VALUE_SIGNED(V)-1))) /* * Returns minimum value for V's type. * Pains are taken (perhaps unnecessarily) to avoid integer overflow * with signed types. * assert: twos complement architecture */ #define INT_VALUE_MIN(V) (-INT_VALUE_MAX(V)-1) 

Pensamiento posterior: estos invocan UB si V es una variable, o una expresión que contiene variables, a las que no se les ha asignado un valor ... que es el caso de la pregunta tal como se hizo. Es probable que funcionen en muchas implementaciones, pero el estándar C no lo garantiza, y sin duda fallarán en una implementación que inicializa variables no inicializadas con valores de captura.

No, tal función no existe en la implementación C estándar.

No puede crear una función que haga esto, pero puede crear algunas macros que lo hagan.

Si tienes C11 puedes usar _Generic :

 #define maxvalue(x) \ _Generic(x, \ char: 127, short: 32767, int: INT_MAX, \ unsigned char: 255, unsigned short: 65535, unsigned int: UINT_MAX) 

Si necesita C89, puede hacerlo si puede diferenciar entre firmado / sin firmar:

 #define maxvalue_unsigned(x) ((1<<(8*sizeof(x)))-1) #define maxvalue_signed(x) ((1<<((8*sizeof(x)-1)))-1) 

Si desea solicitar el nombre de tipo (o usar el nombre de typename específico de typename ), puede usar cadenas:

 #define maxvalue_type(x) maxvalue_helper(#x "----------") unsigned long long maxvalue_helper(const char *s) { switch(*s){ char 'c': /* char */ return 127; char 's': /* short */ return 32767; char 'i': /* int */ return INT_MAX; /* ... */ case 'u': /* unsigned */ switch(9[s]) { case 'c': /* unsigned char */ return 255; char 's': /* unsigned short */ return 65535; char 'i': /* unsigned int */ return UINT_MAX; /* ... */ 

Parece que he podido encontrar una macro relativamente fácil de usar, SIGNED_VAR(VAR) , para probar si la variable entera dada está firmada modificando, comparando y restaurando el valor de la variable (todo eso solo es necesario para los tipos) más pequeño que int ) mientras se evita el comportamiento indefinido, específicamente los tipos relacionados con el desbordamiento firmado y los puntos de secuencia. O eso parece. Al menos, gcc (invocado con -Wall ) no se queja de que esté haciendo locuras entre && y || Operadores, aunque no le gustaban las mismas cosas que el operador ternario ?:

Lo bueno de esta macro es que debería funcionar con comstackdores C89 y C99 ( 1LL puede reemplazarse con 1L y long long puede reemplazarse con solo long (y "%ll" con "%l" , por supuesto) si su C89 el comstackdor no tiene el tipo extendido long long de C99) y también admite correctamente tipos más pequeños que int ( char y short ).

Una vez que sabemos si la variable está firmada o no, la construcción de los valores mínimo y máximo es trivial y muchos han demostrado cómo hacerlo. Las macros VAR_MAX() y VAR_MIN() construyen estos valores y los devuelven como el tipo de entero C99 más long long , long long . Elegí devolver el tipo firmado para evitar posibles problemas de desbordamiento / UB al convertir los valores sin firmar en firmado. Dado que el tipo devuelto long long no puede representar el valor máximo de unsigned long long ( ULLONG_MAX ) directamente como un valor con signo, si ese valor debe devolverse, se devuelve un -1, que después de una ULLONG_MAX unsigned long long producirá ULLONG_MAX . Necesitas tener un poco de cuidado aquí.

Aquí va la fealdad. Esperanza, no me perdí un bicho.

Ah, y, por supuesto, se espera que todo el rango asimétrico de los valores del complemento de 2 se admita en tipos con signo (por ejemplo, min = -128, max = + 127).

EDITAR : He olvidado mencionar que SIGNED_VAR() espera que la variable se inicialice. De lo contrario, leerlo puede resultar en un comportamiento indefinido.

 // file: IntVarMinMax.c // compile: gcc -Wall -std=c99 -O2 IntVarMinMax.c -o IntVarMinMax.exe #include  #include  #include  int SignTestTestVal; unsigned char SignTestOriginalXchar; unsigned short SignTestOriginalXshort; signed char SignTestRestoreOriginalXchar(void) { if (SignTestOriginalXchar < SCHAR_MAX + 1u) return (signed char)SignTestOriginalXchar; return (signed char)(SignTestOriginalXchar - SCHAR_MAX - 1) - SCHAR_MAX - 1; } short SignTestRestoreOriginalXshort(void) { if (SignTestOriginalXshort < SHRT_MAX + 1u) return (short)SignTestOriginalXshort; return (short)(SignTestOriginalXshort - SHRT_MAX - 1) - SHRT_MAX - 1; } #define IFELSE(E1,E2,E3) (((E1) && (E2)) || (!(E1) && (E3))) #define SEQ(E1,E2) (((E1) && (E2)) || (E2)) #define SIGNED_VAR(VAR) \ ( \ IFELSE \ ( \ sizeof(VAR) >= sizeof(int), \ ((VAR) - (VAR) - 1 < 0), \ IFELSE \ ( \ sizeof(VAR) == sizeof(short), \ SEQ(SignTestOriginalXshort = (VAR), \ SEQ(SignTestTestVal = (VAR) = -1, \ SEQ((VAR) = SignTestRestoreOriginalXshort(), \ SignTestTestVal < 0))), \ IFELSE \ ( \ sizeof(VAR) == sizeof(char), \ SEQ(SignTestOriginalXchar = (VAR), \ SEQ(SignTestTestVal = (VAR) = -1, \ SEQ((VAR) = SignTestRestoreOriginalXchar(), \ SignTestTestVal < 0))), \ (fprintf(stderr, "unsupported type!"), exit(-1), 0) \ ) \ ) \ ) \ ) #define VAR_MAX(SIGNED,VAR) \ ( \ SIGNED ? \ ((1ll << (sizeof(VAR) * CHAR_BIT - 2)) - 1 + \ (1ll << (sizeof(VAR) * CHAR_BIT - 2))) : \ ( \ (sizeof(VAR) < sizeof(long long)) ? \ ((1ll << (sizeof(VAR) * CHAR_BIT - 1)) - 1 + \ (1ll << (sizeof(VAR) * CHAR_BIT - 1))) : \ ( \ (sizeof(VAR) == sizeof(long long)) ? \ -1ll : \ (fprintf(stderr, "unsupported type!"), exit(-1), 0) \ ) \ ) \ ) #define VAR_MIN(SIGNED,VAR) \ ( \ SIGNED ? \ (-((1ll << (sizeof(VAR) * CHAR_BIT - 2)) - 1 + \ (1ll << (sizeof(VAR) * CHAR_BIT - 2))) - 1) : \ 0 \ ) int main(void) { signed char sc = 1; char c = 2; unsigned char uc = 3; short ss = 4; unsigned short us = 5; int si = 6; unsigned int ui = 7; long sl = 8; unsigned long ul = 9; long long sll = 10; unsigned long long ull = 11; #define PRINT_VARS() \ printf("sc=%hhd, c=%hhu, uc=%hhu, " \ "ss=%hd, us=%hu, si=%d, ui=%u, " \ "sl=%ld, ul=%lu, sll=%lld, ull=%llu\n", \ sc, c, uc, \ ss, us, si, ui, \ sl, ul, sll, ull) #define TEST_VAR(VAR) \ { \ int varIsSigned = SIGNED_VAR(VAR); \ if (varIsSigned) \ printf("%lld <= " #VAR " <= %lld\n", \ VAR_MIN(varIsSigned,VAR), \ VAR_MAX(varIsSigned,VAR)); \ else \ printf("%lld <= " #VAR " <= %llu\n", \ VAR_MIN(varIsSigned,VAR), \ (unsigned long long)VAR_MAX(varIsSigned,VAR)); \ } PRINT_VARS(); TEST_VAR(sc); TEST_VAR(c); TEST_VAR(uc); TEST_VAR(ss); TEST_VAR(us); TEST_VAR(si); TEST_VAR(ui); TEST_VAR(sl); TEST_VAR(ul); TEST_VAR(sll); TEST_VAR(ull); PRINT_VARS(); return 0; } 

Salida ( ideone ):

 sc=1, c=2, uc=3, ss=4, us=5, si=6, ui=7, sl=8, ul=9, sll=10, ull=11 -128 <= sc <= 127 -128 <= c <= 127 0 <= uc <= 255 -32768 <= ss <= 32767 0 <= us <= 65535 -2147483648 <= si <= 2147483647 0 <= ui <= 4294967295 -2147483648 <= sl <= 2147483647 0 <= ul <= 4294967295 -9223372036854775808 <= sll <= 9223372036854775807 0 <= ull <= 18446744073709551615 sc=1, c=2, uc=3, ss=4, us=5, si=6, ui=7, sl=8, ul=9, sll=10, ull=11 

Se podría hacer fácilmente usando ANSI C 89:

  #include #include int main(void) { printf("Max value of char: %d\n", CHAR_MAX); printf("Min value of char: %d\n", CHAR_MIN); printf("Max value of short: %d\n", SHRT_MAX); printf("Min value of short: %d\n", SHRT_MIN); printf("Max value of int: %d\n", INT_MAX); printf("Min value of int: %d\n", INT_MIN); printf("\n\n"); return 0; } 

Tenga en cuenta que puede incluir float.h y luego usar:

 printf("Max value of Double: %d\n", DBL_MAX); 

Sin embargo, es menos recomendable.

Buena suerte ron