¿Cómo puedo imprimir el resultado de sizeof() en tiempo de compilación en C?

7 minutos de lectura

avatar de usuario
altendky

¿Cómo puedo imprimir el resultado de sizeof() en tiempo de compilación en C?

Por ahora estoy usando una aserción estática (hecha en casa basada en otros recursos web) para comparar el resultado de sizeof() con varias constantes. Si bien esto funciona… está lejos de ser elegante o rápido. También puedo crear una instancia de la variable/estructura y buscar en el archivo de mapa, pero esto también es menos elegante y rápido que una llamada/comando/operador directo. Además, este es un proyecto incrustado que utiliza varios compiladores cruzados… por lo que crear y cargar un programa de muestra en el destino y luego leer un valor es aún más complicado que cualquiera de los anteriores.

En mi caso (antiguo GCC), #warning sizeof(MyStruct) en realidad no interpreta sizeof() antes de imprimir la advertencia.

  • ¿Cuál es la motivación?

    – Ed Heal

    07/01/2014 a las 18:59

  • Para conocer el tamaño de una estructura de varios niveles sin profundizar en el archivo del mapa.

    – altendky

    07/01/2014 a las 19:01

  • Bueno, el preprocesador maneja la declaración de #advertencia incluso antes de que se haya iniciado el compilador adecuado, por lo que no creo que esto sea posible. Supongo que escribir un pequeño programa de prueba, que se invoca como paso personalizado en el proceso de compilación, es una solución. Buena suerte.

    – usuario422005

    07/01/2014 a las 19:43

  • ¿Qué quieres decir con “lejos de… rápido”? Las afirmaciones estáticas se prueban en tiempo de compilación (al igual que sizeof evaluado en tiempo de compilación).

    – mafso

    07/01/2014 a las 20:03

  • Si tiene un compilador de C ++ para su objetivo, puede verificarlo usando stackoverflow.com/questions/2008398/…

    – nos

    07/01/2014 a las 20:57

Estaba jugando buscando una funcionalidad similar cuando me topé con esto:

¿Es posible imprimir el tamaño de una clase de C++ en tiempo de compilación?

Lo que me dio la idea de esto:

char (*__kaboom)[sizeof( YourTypeHere )] = 1;

Lo que da como resultado la siguiente advertencia en VS2015:

warning C4047: 'initializing': 'DWORD (*)[88]' differs in levels of indirection from 'int'

donde 88 en este caso sería la talla que buscas.

Súper hacky, pero funciona. Probablemente un par de años demasiado tarde, pero espero que esto sea útil para alguien.

Todavía no he tenido la oportunidad de probar con gcc o clang, pero intentaré confirmar si funciona o no si alguien no lo hace antes que yo.

Editar: funciona de fábrica para clang 3.6

El único truco que pude conseguir para trabajar para GCC fue abusar -Wformat y hacer que la macro defina una función como la siguiente:

void kaboom_print( void )
{
    printf( "%d", __kaboom );
}

Lo que le dará una advertencia como:

...blah blah blah... argument 2 has type 'char (*)[88]'

Ligeramente más asqueroso que la sugerencia original, pero tal vez alguien que conozca a gcc un poco mejor pueda pensar en una mejor advertencia para el abuso.

  • Al visitar esto un año después, encontré que la solución anterior para gcc ya no funciona (gcc 4.4.2). Después de buscar un poco más, encontré que stackoverflow.com/questions/21001044/… (usando una matriz que es demasiado grande, con -Wframe-larger-than) todavía funciona (debe desplazarse hacia abajo hasta la respuesta aceptada, ya que no está en la parte superior por alguna razón…).

    – fantasma negro

    28 de marzo de 2017 a las 13:47

  • Tuve suerte con una versión reciente de Clang, pero tu enlace también funcionó muy bien.

    –Michael Dorgan

    23 de junio de 2017 a las 18:18

  • ¡Me gusta esta solución! De todos modos, ¿alguien puede eliminar las últimas comillas en el printf en la función kaboom_print? Esto solo me da un error adicional que no me interesa.

    – ola1olsson

    4 de enero de 2018 a las 15:26


  • Gran solución, aunque requiere compilación como C ++ con gcc.

    – jws

    21 de noviembre de 2018 a las 1:49

  • Esto realmente me ahorró algo de tiempo hoy. Lo único extraño es que una aserción estática falla debido a que el tamaño no es X… Haciendo esto para verificar cuál cree el compilador que es el tamaño… dame X: P

    – inquam

    12 oct 2019 a las 13:26

avatar de usuario
JavaMan

Duplicar case constante es un truco que está garantizado para funcionar EN TODOS LOS COMPILADORES C independientemente de cómo cada uno de ellos informe el error. Para Visual C++, es simple:

struct X {
    int a,b;
    int c[10];
};
int _tmain(int argc, _TCHAR* argv[])
{
    int dummy;

    switch (dummy) {
    case sizeof(X):
    case sizeof(X):
        break;
    }
    return 0;
}

Resultado de la compilación:

 ------ Build started: Project: cpptest, Configuration: Debug Win32 ------
 cpptest.cpp c:\work\cpptest\cpptest\cpptest.cpp(29): error C2196: case value '48' already used
 ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Entonces el tamaño de la estructura X es 48

EDITADO (3jun2020): Para gcc o cualquier otro compilador que solo imprima “valor de caso duplicado”, uso este truco para reducir el valor:

1) agregue un valor de caso 1 == 2 (para representar falso)

2) por prueba y error, reduzca el valor, por ejemplo, trato de adivinar el sizeof(X) es >16:

#include <stdio.h>
typedef struct _X {
    int a;
    char b[10];
} X;
int main()
{
    printf("Hello World");

    int dummy=0   ;
    switch (dummy) {
    case  1==2:
    case sizeof( X)>16:
    //case 16:
    break;
    }
    return 0;
}

resultado:

main.c: In function ‘main’:
main.c:14:5: error: duplicate case value
     case sizeof( X)>16:
     ^~~~
main.c:13:5: error: previously used here
     case  1==2:

por lo que es falso, es decir, tamaño de (X) <= 16.

3) repetir con algunos otros valores sensibles. por ejemplo, trate de adivinar que es 16, es decir sizeof(X)==16. Si no se queja del valor del caso duplicado. Entonces la expresión es verdadera.

4) opcionalmente añadir un case 16 para verificarlo por ejemplo

#include <stdio.h>
typedef struct _X {
    int a;
    char b[10];
} X;
int main()
{
    printf("Hello World");

    int dummy=0   ;
    switch (dummy) {
   // case  1==2:
    case sizeof( X):
    case 16:
    break;
    }
    return 0;
}

resultado

main.c: In function ‘main’:
main.c:15:5: error: duplicate case value
     case 16:
     ^~~~
main.c:14:5: error: previously used here
     case sizeof( X):

confirmando que sizeof(X) es 16.

Alternativamente, se observa que gcc puede reportar múltiples duplicados, por lo que este truco es posible para hacer múltiples conjeturas en una sola pasada:

#include <stdio.h>
typedef struct _X {
    int a;
    char b[10];
} X;
int main()
{
    printf("Hello World");

    int dummy=0   ;
    switch (dummy) {
    case  1==2: //represents false
    case 1==1: //represents true
    case sizeof( X)>10:
    case sizeof( X)>12:
    case sizeof( X)>14:
    case sizeof( X)>16:
    case  sizeof( X)==16:
    //case 16:
    break;
    }
    return 0;
}

resultado

main.c: In function ‘main’:
main.c:14:5: error: duplicate case value
     case sizeof( X)>10:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:15:5: error: duplicate case value
     case sizeof( X)>12:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:16:5: error: duplicate case value
     case sizeof( X)>14:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~
main.c:17:5: error: duplicate case value
     case sizeof( X)>16:
     ^~~~
main.c:12:5: error: previously used here
     case  1==2:
     ^~~~
main.c:18:5: error: duplicate case value
     case  sizeof( X)==16:
     ^~~~
main.c:13:5: error: previously used here
     case 1==1:
     ^~~~

sugiriendo el sizeof(X) es >10, >12, >14 pero no es >16. El ==16 se agrega como suposición final.

  • Desafortunadamente, no funciona en mi versión anterior de gcc 4.2.0, solo dice ‘valor de caso duplicado’ sin imprimir el valor.

    – sononancia

    09/03/2017 a las 13:30


  • algunos métodos generales para imprimir valores int calculados durante la compilación: stackoverflow.com/questions/28852574/…

    – JavaMan

    8 de junio de 2017 a las 8:46


  • este fue el unico que funciono con gcc en c para mi

    – Miguel

    15 oct 2018 a las 17:28

  • editado para usar el truco en gcc que solo imprime “valor de caso duplicado” sin imprimir el valor de caso real.

    – JavaMan

    2 de junio de 2020 a las 19:29

  • ¿Por qué no es esta la mejor respuesta? Funciona para mí con MSVS C ++

    – Tatiana Racheva

    4 de agosto de 2021 a las 21:33

avatar de usuario
Ruslán

La siguiente forma, que funciona en GCC, Clang, MSVC y más, incluso en versiones anteriores, se basa en la conversión fallida de un parámetro de función de puntero a matriz a un tipo escalar. Los compiladores imprimen el tamaño de la matriz, por lo que puede obtener el valor de la salida. Funciona tanto en modo C como C++.

Código de ejemplo para averiguarlo sizeof(long) (jugar con él en línea):

char checker(int);
char checkSizeOfInt[sizeof(long)]={checker(&checkSizeOfInt)};

Ejemplos de resultados relevantes:

  • CCG 4.4.7

<source>:1: note: expected 'int' but argument is of type 'char (*)[8]'

  • sonido metálico 3.0.0

<source>:1:6: note: candidate function not viable: no known conversion from 'char (*)[8]' to 'int' for 1st argument;

  • MSVC 19.14

<source>(2): warning C4047: 'function': 'int' differs in levels of indirection from 'char (*)[4]'

avatar de usuario
Konstantin Stupnik

Una forma más (que realmente funciona):

char __foo[sizeof(MyStruct) + 1] = {[sizeof(MyStruct)] = ""};

Funciona con old’ish gcc 5.x. Produce un error como este:

a.c:8:54: error: initializer element is not computable at load time
a.c:8:54: note: (near initialization for 'a[8]')

ps obviamente, este es (muy) específico de gcc. Todos los demás métodos no funcionaban para mí.

Solución rápida y sencilla que funcionó para mí (GCC):

(char[sizeof(long long)])"bla";

Esto da como resultado un mensaje de error que revela el tamaño de long long:

ISO C++ forbids casting to an array type 'char [8]'

  • Tenga en cuenta que esto en realidad se compiló para mí en VS 2019. Pero cambiar “bla” a un número (por ejemplo, 4) trabajó.

    – por defecto

    14/09/2021 a las 14:42

avatar de usuario
HIPERPOLLO

Me topé con una solución similar a la gran solución de Bakhazard, y esta produce una advertencia mucho menos detallada, por lo que puede resultarle útil:

char (*__fail)(void)[sizeof(uint64_t)] = 1;

Esto produce el mensaje de error.

Function cannot return array type 'char [8]'

Esto fue probado con la última versión de clang(1).

  • Tenga en cuenta que esto en realidad se compiló para mí en VS 2019. Pero cambiar “bla” a un número (por ejemplo, 4) trabajó.

    – por defecto

    14/09/2021 a las 14:42

@jws buena idea!. Sin embargo, sizeof(xxx) es una expresión constante (excepto VLA, https://en.cppreference.com/w/c/language/sizeof), por lo que el operador sizeof debería funcionar incluso en la selección de casos:

enum e1 {dummy=-1};
enum e1 ev;
switch (ev) {
    case sizeof(myType):;
    break;
    default:;
}

.. funciona en mi GCC: “..\WinThreads.c:18:9: advertencia: valor de caso ‘4’ no en el tipo enumerado ‘enum e1’ [-Wswitch] “

  • Trabajó para mí con gcc versión 8.3.0

    –Sneh Shikhar

    23 de abril de 2020 a las 9:04

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad