How can I print the result of sizeof() at compile time in C?

后端 未结 12 1306
星月不相逢
星月不相逢 2020-11-29 20:47

How can I print the result of sizeof() at compile time in C?

For now I am using a static assert (home brewed based on other web resources) to compare the sizeof() re

相关标签:
12条回答
  • 2020-11-29 21:22

    Though this isn't exactly at compile time, it is before runtime, so it could still be relevant for some people.

    You can define an array like so:

    uint8_t __some_distinct_name[sizeof(YourTypeHere)];
    

    And then, after compilation, get the size from the object file:

    $ nm -td -S your_object_file |       # list symbols and their sizes, in decimal
      grep ' __some_distinct_name$' |    # select the right one
      cut -d' ' -f2 |                    # grab the size field
      xargs printf "Your type is %d B\n" # print
    
    0 讨论(0)
  • 2020-11-29 21:23

    Duplicate case constant is a trick that is guaranteed to work IN ALL C COMPILERS regardless of how each of them reports error. For Visual C++, it is 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;
    }
    

    Compilation result:

     ------ 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 ==========
    

    So sizeof the struct X is 48

    EDITED (3jun2020): For gcc or any other compilers that only print "duplicate case value", I use this trick to narrow down the value:

    1) add a case value 1==2 (to represent false)

    2) by trial and error, narrow down the value e.g. I try to guess the sizeof(X) is >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;
    }
    

    result:

    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:
    

    so it is false, i.e. sizeof(X)<=16.

    3) repeat with some other sensible values. e.g. try to guess that it is 16 i.e. sizeof(X)==16. If it doesn't complain about duplicate case value. Then the expression is true.

    4) optionally add a case 16 to verify it e.g.

    #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;
    }
    

    result

    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):
    

    confirming that sizeof(X) is 16.

    Alternatively, it is observed that gcc can report multiple duplicates, so this trick is possible for making multiple guesses on a single pass:

    #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;
    }
    

    result

    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:
         ^~~~
    

    suggesting the sizeof(X) is >10, >12, >14 but is not >16. The ==16 is added as a final guess.

    0 讨论(0)
  • 2020-11-29 21:25

    I was mucking around looking for similar functionality when I stumbled on this:

    Is it possible to print out the size of a C++ class at compile-time?

    Which gave me the idea for this:

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

    Which results in the following warning in VS2015:

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

    where 88 in this case would be the size you're looking for.

    Super hacky, but it does the trick. Probably a couple years too late, but hopefully this will be useful to someone.

    I haven't had a chance to try with gcc or clang yet, but I'll try to confirm whether or not it works if someone doesn't get to it before me.

    Edit: Works out of the box for clang 3.6

    The only trick I could get to work for GCC was abusing -Wformat and having the macro define a function like the following:

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

    Which will give you a warning like:

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

    Slightly more gross than the original suggestion, but maybe someone who knows gcc a bit better can think of a better warning to abuse.

    0 讨论(0)
  • 2020-11-29 21:28

    Quick and simple solution that worked for me (GCC):

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

    This results in an error message that reveals the size of long long:

    ISO C++ forbids casting to an array type 'char [8]'
    
    0 讨论(0)
  • 2020-11-29 21:30

    The following way, which works in GCC, Clang, MSVC and more, even in older versions, is based on failed conversion of a function parameter from pointer to array to a scalar type. The compilers do print size of the array, so you can get the value from the output. Works both in C and C++ mode.

    Example code to find out sizeof(long) (play with it online):

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

    Examples of relevant output:

    • GCC 4.4.7

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

    • clang 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]'

    0 讨论(0)
  • 2020-11-29 21:30
    //main.cpp
    #include <cstddef>
    template <std::size_t x>
    struct show_size;
    
    void foo()
    {
        show_size<sizeof(my_type)>();//!!please change `my_type` to your expected
    }
    
    int main()
    {
        return 0;
    }
    

    You can compile this pretty simple code, and during its pre-compilation stage, the compiler will give error, in which the sizeof(my_type) will give concrete value. e.g.:

    g++ main.cpp
    
    0 讨论(0)
提交回复
热议问题