¿Hay alguna forma de utilizar una sizeof
macro en un preprocesador?
Por ejemplo, ha habido un montón de situaciones a lo largo de los años en las que quería hacer algo como:
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
Lo que estoy comprobando aquí está completamente inventado; el punto es que a menudo me gusta poner este tipo de comprobaciones en tiempo de compilación (tamaño o alineación) para evitar que alguien modifique una estructura de datos que podría desalinearse o volver a alinearse. cosas de tamaño que las romperían.
No hace falta decir que no parece que pueda usar un sizeof
de la manera descrita anteriormente.
Respuestas:
Hay varias maneras de hacer esto. Los siguientes fragmentos no producirán código si son
sizeof(someThing)
igualesPAGE_SIZE
; de lo contrario, producirán un error en tiempo de compilación.1. C11 way
A partir de C11 puede usar
static_assert
(requiere#include <assert.h>
).Uso:
2. Macro personalizada
Si solo desea obtener un error en tiempo de compilación cuando
sizeof(something)
no es lo que esperaba, puede usar la siguiente macro:Uso:
Este artículo explica en detalle por qué funciona.
3. Específico para EM
En el compilador de Microsoft C ++ puede usar la macro C_ASSERT (requiere
#include <windows.h>
), que usa un truco similar al descrito en la sección 2.Uso:
fuente
gcc
(probado en la versión 4.8.4) (Linux). En los((void)sizeof(...
errores de it conexpected identifier or '(' before 'void'
yexpected ')' before 'sizeof'
. Pero en principio, ensize_t x = (sizeof(...
cambio, funciona según lo previsto. Tienes que "usar" el resultado, de alguna manera. Para permitir que esto se llame varias veces, ya sea dentro de una función o en el ámbito global, algo comoextern char _BUILD_BUG_ON_ [ (sizeof(...) ];
se puede usar repetidamente (sin efectos secundarios, en realidad no hace referencia a_BUILD_BUG_ON_
ninguna parte).No. Las directivas condicionales toman un conjunto restringido de expresiones condicionales;
sizeof
es una de las cosas no permitidas.Las directivas de preprocesamiento se evalúan antes de que se analice la fuente (al menos conceptualmente), por lo que aún no hay tipos o variables para obtener su tamaño.
Sin embargo, existen técnicas para obtener aserciones en tiempo de compilación en C (por ejemplo, consulte esta página ).
fuente
Sé que es una respuesta tardía, pero para agregar a la versión de Mike, aquí hay una versión que usamos que no asigna memoria. No se me ocurrió la verificación de tamaño original, lo encontré en Internet hace años y, lamentablemente, no puedo hacer referencia al autor. Los otros dos son solo extensiones de la misma idea.
Debido a que son typedef, no se asigna nada. Con __LINE__ en el nombre, siempre es un nombre diferente para que se pueda copiar y pegar donde sea necesario. Esto funciona en compiladores de MS Visual Studio C y compiladores de GCC Arm. No funciona en CodeWarrior, CW se queja de la redefinición, no hace uso de la construcción del preprocesador __LINE__.
fuente
#define STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
Sé que este hilo es muy antiguo pero ...
Mi solución:
Siempre que esa expresión sea igual a cero, se compilará bien. Cualquier otra cosa y explota allí mismo. Debido a que la variable es externa, no ocupará espacio y, siempre que nadie haga referencia a ella (lo que no hará), no causará un error de enlace.
No es tan flexible como la macro de aserción, pero no pude hacer que se compilara en mi versión de GCC y esto lo hará ... y creo que se compilará en casi cualquier lugar.
fuente
Las respuestas existentes solo muestran cómo lograr el efecto de "aserciones en tiempo de compilación" basadas en el tamaño de un tipo. Eso puede satisfacer las necesidades del OP en este caso particular, pero hay otros casos en los que realmente necesita un preprocesador condicional basado en el tamaño de un tipo. He aquí cómo hacerlo:
Escribe un pequeño programa en C como:
Compila eso. Escriba un script en su lenguaje de script favorito, que ejecute el programa C anterior y capture su salida. Utilice esa salida para generar un archivo de encabezado C. Por ejemplo, si estuviera usando Ruby, podría verse así:
Luego agregue una regla a su Makefile u otro script de compilación, lo que hará que ejecute el script anterior para compilar
sizes.h
.Incluya
sizes.h
siempre que necesite utilizar condicionales de preprocesador según los tamaños.¡Hecho!
(¿Alguna vez ha escrito
./configure && make
para crear un programa? Lo queconfigure
hacen los scripts es básicamente como el anterior ...)fuente
¿Qué pasa con la siguiente macro?
Por ejemplo, en el comentario MSVC dice algo como:
fuente
#if
directiva de preprocesador.Solo como referencia para esta discusión, informo que algunos compiladores obtienen sizeof () ar tiempo de preprocesador.
La respuesta de JamesMcNellis es correcta, pero algunos compiladores pasan por esta limitación (esto probablemente viola la estricta ansi c).
Como ejemplo de esto, me refiero al compilador C de IAR (probablemente el principal para microcontroladores profesionales / programación integrada).
fuente
sizeof
en el momento del preprocesamiento.sizeof
debe tratarse solo como un identificador.#if (sizeof(int) == 8)
realmente funcionaban (en algunos compiladores)". La respuesta: "Debe haber sido antes de mi tiempo", fue de Dennis Ritchie.#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
Podría funcionarfuente
#define SIZEOF_TYPE(x) (((x*)0) + 1)
#if
condición. No proporciona ningún beneficio sobresizeof(x)
.En C11
_Static_assert
se agrega la palabra clave. Se puede usar como:fuente
En mi código portátil de C ++ ( http://www.starmessagesoftware.com/cpcclibrary/ ) quería poner una guardia segura en los tamaños de algunas de mis estructuras o clases.
En lugar de encontrar una forma para que el preprocesador arroje un error (que no puede funcionar con sizeof () como se indica aquí), encontré una solución aquí que hace que el compilador arroje un error. http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
Tuve que adaptar ese código para que arrojara un error en mi compilador (xcode):
fuente
Después de probar las macro mencionadas, este fragmento parece producir el resultado deseado (
t.h
):Corriendo
cc -E t.h
:Corriendo
cc -o t.o t.h
:42 no es la respuesta a todo después de todo ...
fuente
Para comprobar en el momento de la compilación el tamaño de las estructuras de datos frente a sus limitaciones, he utilizado este truco.
Si el tamaño de x es mayor o igual que su límite MAX_SIZEOF_X, entonces el gcc se quejará con un error de 'el tamaño de la matriz es demasiado grande'. VC ++ emitirá el error C2148 ('el tamaño total de la matriz no debe exceder 0x7fffffff bytes') o C4266 'no puede asignar una matriz de tamaño constante 0'.
Las dos definiciones son necesarias porque gcc permitirá definir una matriz de tamaño cero de esta manera (tamaño de x - n).
fuente
El
sizeof
operador no está disponible para el preprocesador, pero puede transferirlosizeof
al compilador y verificar la condición en tiempo de ejecución:fuente
compiler_size
? ¿Qué intenta mostrar tu ejemplo?