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.
All you need is a trick that causes the compiler to complain about some compile time integer values being used incorrectly, like duplicated case
constant:
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;
}
------ 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
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.
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]'
I stumbled upon a solution similar to Bakhazard's great solution, and this one produces a much less verbose warning, so you may find it useful:
char (*__fail)(void)[sizeof(uint64_t)] = 1;
This produces the error message
Function cannot return array type 'char [8]'
This was tested with the latest version of clang(1)
.
My gcc C compiler refuses to print the size using any of the above solutions. I inverted the logic to inject compiler warnings for what size it is not.
enum e
{
X = sizeof(struct mystruct)
};
void foo()
{
static enum e ev;
switch (ev)
{
case 0:
case 4:
case 8:
case 12:
case 16:
case 20:
break;
}
}
Then I have to look through the warnings for the missing number.
warning: case value '0' not in enumerated type 'e' [-Wswitch]
warning: case value '4' not in enumerated type 'e' [-Wswitch]
warning: case value '12' not in enumerated type 'e' [-Wswitch]
warning: case value '16' not in enumerated type 'e' [-Wswitch]
warning: case value '20' not in enumerated type 'e' [-Wswitch]
So then my struct size is 8.
My packing is 4.
Meh... it's an option.
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
@jws nice idea!. Howewer, sizeof(xxx) is a constant expression (except VLA, https://en.cppreference.com/w/c/language/sizeof), so the sizeof operator should work even in the case selection:
enum e1 {dummy=-1};
enum e1 ev;
switch (ev) {
case sizeof(myType):;
break;
default:;
}
.. it work in my GCC: "..\WinThreads.c:18:9: warning: case value '4' not in enumerated type 'enum e1' [-Wswitch] "
You can't do this, not with structures. The preprocessor is invoked before compilation takes place, so there isn't even the concept of structure; you can't evaluate the size of something that doesn't exist / wasn't defined. The preprocessor does tokenize a translation unit, but it does so only for the purpose of locating macro invocation.
The closest thing you can have is to rely on some implementation-defined macros that evaluate to the size of built-in types. In gcc, you can find those with:
gcc -dM -E - </dev/null | grep -i size
Which in my system printed:
#define __SIZE_MAX__ 18446744073709551615UL
#define __SIZEOF_INT__ 4
#define __SIZEOF_POINTER__ 8
#define __SIZEOF_LONG__ 8
#define __SIZEOF_LONG_DOUBLE__ 16
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_WINT_T__ 4
#define __SIZE_TYPE__ long unsigned int
#define __SIZEOF_PTRDIFF_T__ 8
#define __SIZEOF_FLOAT__ 4
#define __SIZEOF_SHORT__ 2
#define __SIZEOF_INT128__ 16
#define __SIZEOF_WCHAR_T__ 4
#define __SIZEOF_DOUBLE__ 8
#define __SIZEOF_LONG_LONG__ 8
There is really nothing you can do to know the size of a custom struct without writing a program and executing it.
来源:https://stackoverflow.com/questions/20979565/how-can-i-print-the-result-of-sizeof-at-compile-time-in-c