How can I print the result of sizeof() at compile time in C?
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() result to various constants. While this works... it is far from elegant or fast. I can also create an instance of the variable/struct and look in the map file but this is also less elegant and fast than a direct call/command/operator. Further, this is an embedded project using multiple cross-compilers... so building and loading a sample program to the target and then reading out a value is even more of a hassle than either of the above.
In my case (old GCC), #warning sizeof(MyStruct)
does not actually interpret sizeof() before printing the warning.
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.
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.
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]'
One more way (that actually works):
char __foo[sizeof(MyStruct) + 1] = {[sizeof(MyStruct)] = ""};
Works with old'ish gcc 5.x. Yields an error like this:
a.c:8:54: error: initializer element is not computable at load time
a.c:8:54: note: (near initialization for 'a[8]')
p.s. obviously, this one is (very) gcc specific. All other methods weren't working for me.