问题
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.
回答1:
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.
回答2:
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;
}
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
回答3:
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.
回答4:
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]'
回答5:
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)
.
回答6:
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.
回答7:
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
回答8:
@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] "
回答9:
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