proteus - ¿Cómo puedo usar "sizeof" en una macro de preprocesador?
pic c compiler ejemplos (11)
¿Hay alguna forma de usar un "
sizeof
" en una macro de pre-procesador?
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 la fuente se analice (al menos conceptualmente), por lo que aún no hay ningún tipo o variable para obtener su tamaño.
Sin embargo, hay técnicas para obtener aserciones en tiempo de compilación en C (por ejemplo, consulte esta página ).
¿Hay alguna forma de usar un sizeof
en una macro de preprocesador?
Por ejemplo, ha habido un montón de situaciones en los últimos 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 verificando aquí está completamente inventado; el punto es que a menudo me gusta poner estos tipos de controles de compilación en tiempo (de tamaño o de alineación) para evitar que alguien modifique una estructura de datos que podría desalinearse o volverse incorrecta. Tamaño cosas que los romperían.
No hace falta decir que no parece poder usar un sizeof
de la manera descrita anteriormente.
¿Qué pasa con la siguiente macro?
/*
* Simple compile time assertion.
* Example: CT_ASSERT(sizeof foo <= 16, foo_can_not_exceed_16_bytes);
*/
#define CT_ASSERT(exp, message_identifier) /
struct compile_time_assertion { /
char message_identifier : 8 + !(exp); /
}
Por ejemplo, en un comentario, MSVC dice algo así como:
test.c(42) : error C2034: ''foo_can_not_exceed_16_bytes'' : type of bit field too small for number of bits
El operador sizeof
no está disponible para el preprocesador, pero puede transferir sizeof
al compilador y verificar la condición en tiempo de ejecución:
#define elem_t double
#define compiler_size(x) sizeof(x)
elem_t n;
if (compiler_size(elem_t) == sizeof(int)) {
printf("%d",(int)n);
} else {
printf("%lf",(double)n);
}
En C11 se _Static_assert
palabra clave _Static_assert
. Se puede usar como:
_Static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn''t match page size")
En mi código portable de C ++ ( http://www.starmessagesoftware.com/cpcclibrary/ ) quise poner una guardia segura sobre el tamaño de algunas de mis estructuras o clases.
En lugar de encontrar una forma de 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):
static union
{
char int8_t_incorrect[sizeof( int8_t) == 1 ? 1: -1];
char uint8_t_incorrect[sizeof( uint8_t) == 1 ? 1: -1];
char int16_t_incorrect[sizeof( int16_t) == 2 ? 1: -1];
char uint16_t_incorrect[sizeof(uint16_t) == 2 ? 1: -1];
char int32_t_incorrect[sizeof( int32_t) == 4 ? 1: -1];
char uint32_t_incorrect[sizeof(uint32_t) == 4 ? 1: -1];
};
Hay varias maneras de hacer esto. Los siguientes fragmentos no generarán código si sizeof(someThing)
es igual a PAGE_SIZE
; de lo contrario, producirán un error en tiempo de compilación.
1. C11 manera
Comenzando con C11 puedes usar static_assert
.
Uso:
static_assert(sizeof(someThing) == PAGE_SIZE, "Data structure doesn''t match page size");
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:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
Uso:
BUILD_BUG_ON( sizeof(someThing) != PAGE_SIZE );
Este artículo explica en detalles por qué funciona.
3. Específico de MS
En el compilador de Microsoft C ++ puede usar la macro C_ASSERT (requiere #include <windows.h>
), que utiliza un truco similar al descrito en la sección 2.
Uso:
C_ASSERT(sizeof(someThing) == PAGE_SIZE);
Las respuestas existentes solo muestran cómo lograr el efecto de "afirmaciones 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 de C como:
/* you could call this sizeof_int.c if you like... */
#include <stdio.h>
/* ''int'' is just an example, it could be any other type */
int main(void) { printf("%zd", sizeof(int); }
Compila eso. Escriba un script en su lenguaje de scripting favorito, que ejecuta el programa C anterior y captura su salida. Use esa salida para generar un archivo de encabezado C. Por ejemplo, si usabas Ruby, podría verse así:
sizeof_int = `./sizeof_int`
File.open(''include/sizes.h'',''w'') { |f| f.write(<<HEADER) }
/* COMPUTER-GENERATED, DO NOT EDIT BY HAND! */
#define SIZEOF_INT #{sizeof_int}
/* others can go here... */
HEADER
A continuación, agregue una regla a su Makefile u otra secuencia de comandos de compilación, lo que hará que ejecute la secuencia de comandos anterior para crear sizes.h
.
Incluya los sizes.h
donde sea que necesite usar los condicionales del preprocesador según los tamaños.
¡Hecho!
(¿Alguna vez ha escrito ./configure && make
para crear un programa? Lo que hacen los scripts de configure
es básicamente como el de arriba ...)
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ó el control 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 pueda copiarse y pegarse donde sea necesario. Esto funciona en compiladores de MS Visual Studio C y en compiladores GCC Arm. No funciona en CodeWarrior, CW se queja de la redefinición, no hace uso de la construcción del preprocesador __LINE__.
//Check overall structure size
typedef char p__LINE__[ (sizeof(PARS) == 4184) ? 1 : -1];
//check 8 byte alignment for flash write or similar
typedef char p__LINE__[ ((sizeof(PARS) % 8) == 0) ? 1 : 1];
//check offset in structure to ensure a piece didn''t move
typedef char p__LINE__[ (offsetof(PARS, SUB_PARS) == 912) ? 1 : -1];
Sé que este hilo es muy viejo, pero ...
Mi solución:
extern char __CHECK__[1/!(<<EXPRESSION THAT SHOULD COME TO ZERO>>)];
Mientras esa expresión sea igual a cero, compila bien. Algo más y explota allí mismo. Debido a que la variable es externa, no ocupará espacio, y mientras nadie lo haga referencia (lo que no harán) no causará un error de enlace.
No es tan flexible como la macro afirmar, pero no pude conseguir que se compile en mi versión de GCC y esto será ... y creo que se compilará prácticamente en cualquier lugar.
Solo como referencia para esta discusión, informo que algunos compiladores obtienen un tamaño de () un tiempo previo al procesador.
La respuesta de JamesMcNellis es correcta, pero algunos compiladores pasan por esta limitación (esto probablemente viola la ansi c estricta).
Como un caso de esto, me refiero al compilador C de IAR (probablemente el primero para microcontroladores profesionales / programación integrada).
#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
podría funcionar