visual variable una son relacionales que operadores net logicos las inicializar declarar constantes constante comparacion como c linux-kernel macros language-lawyer

variable - que son las constantes en visual basic o visual net



Detección de expresiones enteras constantes en macros (2)

No tengo una solución para sizeof(void) no sea estándar, pero podría evitar la posibilidad de que sizeof(void) == sizeof(int) haciendo algo como:

#define ICE_P(x) ( / sizeof(void) != / sizeof(*( / 1 ? / ((void*) ((x) * 0L) ) : / ((struct { char v[sizeof(void) * 2]; } *) 1) / ) / ) / )

Sé que no es una respuesta completa, pero está un poco más cerca ...

Editar : He investigado un poco sobre qué soluciones funcionan en varios compiladores. He codificado toda la siguiente información en Hedley ; vea las HEDLEY_IS_CONSTANT , HEDLEY_REQUIRE_CONTEXPR y HEDLEY__IS_CONSTEXPR . Es de dominio público y un solo encabezado, por lo que es muy fácil ingresar en tu proyecto o puedes copiar los bits que te interesan.

C11 Macro y variantes

La macro C11 de user2357112 debería funcionar en cualquier compilador C11, pero SunCC y PGI están actualmente rotos, así que tendrás que ponerlos en una lista negra. Además, IAR define __STDC_VERSION__ en modo C ++, y este truco no funciona en C ++ (AFAIK nada lo hace ), por lo que es probable que desee asegurarse de que __cplusplus no esté definido. He verificado que realmente funciona en GCC, clang (y compiladores derivados de clang como emscripten), ICC, IAR y XL C / C ++.

Aparte de eso, algunos compiladores admiten _Generic incluso en modos anteriores como una extensión:

  • GCC 4.9+
  • sonido metálico; consulte con __has_feature(c_generic_selections) (aunque es posible que desee desactivar la advertencia -Wc11-extensions )
  • ICC 16.0+
  • XL C / C ++ 12.1+

Además, tenga en cuenta que a veces los compiladores emiten una advertencia cuando lanzas un int a un void* ; Puedes evitar esto al intptr_t primero a un intptr_t luego a void* :

#define ICE_P(expr) _Generic((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)

O bien, para los compiladores (como GCC) que definen __INTPTR_TYPE__ , puede usar eso en lugar de intptr_t y no necesita incluir stdint.h .

Otra posible implementación aquí es usar __builtin_types_compatible_p lugar de _Generic . No conozco ningún compilador en el que eso funcione, pero la macro original no lo haría, pero te saca de una -Wpointer-arith :

#define IS_CONSTEXPR(expr) / __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)

Esta versión debería funcionar con GCC en 3.1, al igual que los compiladores que definen __GNUC__ / __GNUC_MINOR__ a valores que indican ≥ 3.1 como clang e ICC.

Macro de esta respuesta

Cualquier compilador que admita sizeof(void) debería funcionar, pero existe una buena posibilidad de que se ejecute una advertencia (como -Wpointer-arith ). Dicho esto, los compiladores de AFAICT que soportan sizeof(void) parecen haberlo hecho siempre, por lo que cualquier versión de estos compiladores debería funcionar:

  • GCC
  • Clang (y compiladores incorporados, que también definen __clang__ )
  • ICC (probado 18.0)
  • XL C / C ++ (probado 13.1.6)
  • TI (probado 8.0)
  • TinyCC

__builtin_constant_p

Dependiendo de su caso de uso, puede ser preferible usar __builtin_constant_p en los compiladores que lo soportan. Es un poco más general (y más nebuloso) que una expresión constante entera; solo dice que el compilador conoce el valor en tiempo de compilación. Se sabe que estos compiladores lo admiten:

  • GCC 3.1+
  • Sonido metálico
  • ICC (probado 18.0)
  • TinyCC 0.9.19+
  • brazocc 5.04+
  • XL C / C ++ (no documentado, pero definitivamente funciona en 13.1.6+)

Si usa la macro para elegir entre una ruta de código que el compilador puede doblar constantemente si conoce el valor en tiempo de compilación pero es lento en tiempo de ejecución y una ruta de código que es una caja negra para el compilador pero es rápida en tiempo de ejecución, use __builtin_constant_p .

OTOH, si quiere verificar que el valor sea realmente un ICE según el estándar, no use __builtin_constant_p . Como ejemplo, aquí hay una macro que devolverá expr si el expr es un ICE, pero -1 si no lo es:

#if defined(ICE_P) # define REQUIRE_ICE(expr) (ICE_P(expr) ? (expr) : (-1)) #else # define REQUIRE_ICE(expr) (expr) #endif

Puede usar eso al declarar una matriz en una macro si el compilador muestra un error si usa un VLA:

char foo[REQUIRE_ICE(bar)];

Dicho esto, GCC y clang implementan una advertencia -Wvla que puede usar en su lugar. La ventaja de -Wvla es que no requiere modificaciones del código fuente (es decir, puede escribir char foo[bar]; ). Las desventajas son que no es tan ampliamente compatible, y que el uso de parámetros de matriz conformes también desencadenará el diagnóstico, por lo que si desea evitar muchos falsos positivos, esta macro puede ser su mejor opción.

Compiladores que no admiten nada

  • MSVC
  • DMC

Ideas bienvenidas :)

Hubo una discusión en la lista de correo del kernel de Linux con respecto a una macro que prueba si su argumento es una expresión constante entera y es una expresión constante entera.

Un enfoque particularmente ingenioso que no utiliza edificios internos, propuesto por Martin Uecker ( inspiration en tgmath.h de glibc ), es:

#define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1)))

Esta macro se expande en una expresión constante entera del valor 1 si el argumento es una expresión constante entera, 0 caso contrario. Sin embargo, depende de sizeof(void) para ser permitido (y diferente de sizeof(int) ), que es una extensión GNU C.

¿Es posible escribir una macro sin edulcorados y sin depender de las extensiones de lenguaje? Si es así, ¿evalúa su argumento?

Para una explicación de la macro que se muestra arriba, vea en su lugar: Macro del kernel de Linux __is_constexpr


Use la misma idea, donde el tipo de expresión a ?: depende de si un argumento es una constante de puntero nulo o un void * normal void * , pero detecta el tipo con _Generic :

#define ICE_P(x) _Generic((1? (void *) ((x)*0) : (int *) 0), int*: 1, void*: 0)

Demostración en Ideone. _Generic es una adición C11, por lo que si está atascado en C99 o algo antes, no podrá usarlo.

Además, tiene enlaces estándar para la definición de una constante de puntero nulo y la forma en que las constantes de puntero nulo interactúan con el tipo de una expresión ?:

Una expresión constante entera con el valor 0, o una expresión de este tipo para escribir void *, se llama constante de puntero nulo.

y

Si el segundo y tercer operandos son punteros o uno es una constante de puntero nulo y el otro es un puntero, el tipo de resultado es un puntero a un tipo calificado con todos los calificadores de tipo de los tipos a los que hacen referencia ambos operandos. Además, si ambos operandos son punteros a tipos compatibles o a versiones calificadas de manera diferente de tipos compatibles, el tipo de resultado es un puntero a una versión apropiadamente calificada del tipo compuesto; si un operando es una constante de puntero nulo, el resultado tiene el tipo del otro operando; de lo contrario, un operando es un puntero a void o una versión calificada de void, en cuyo caso el tipo de resultado es un puntero a una versión de void apropiadamente calificada .