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
@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] "
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.
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)
.
This is a generic solution for any C compilers.
I've realized that if our aim is knowing the value of a sizeof()
instead of printing out its value, then we just need to evaluate a few compile time sizeof(X)>??
expressions to narrow down the value.
The trick is to produce compile time errors when the expressions evaluate to false
(zero) or true
(non-zero).
Many standard C constructs can achieve our goal. The duplicate case
value trick i described separately is one of them. Another one is through test for division by zero in an initializer which the compiler evaluates at compile time. For example, to get the size of X:
struct _X {
int a;
char c;
double d;
float f[30];
} X;
compile with a few lines:
#include <stdio.h>
struct _X {
int a;
char c;
double d;
float f[30];
} X;
int r2=1/(sizeof(X)<170);
int r3=1/(sizeof(X)<100);
int r4=1/(sizeof(X)<80);
int r5=1/(sizeof(X)<60);
int main()
{
return 0;
}
result
main.c:17:9: warning: division by zero [-Wdiv-by-zero]
int r3=1/(sizeof(X)<100);
^
main.c:17:8: error: initializer element is not constant
int r3=1/(sizeof(X)<100);
^
main.c:18:9: warning: division by zero [-Wdiv-by-zero]
int r4=1/(sizeof(X)<80);
^
main.c:18:8: error: initializer element is not constant
int r4=1/(sizeof(X)<80);
^
main.c:19:9: warning: division by zero [-Wdiv-by-zero]
int r5=1/(sizeof(X)<60);
^
main.c:19:8: error: initializer element is not constant
int r5=1/(sizeof(X)<60);
^
implying sizeof(X)<170
is true
(non-zero) but sizeof(X)<100
is false
(causing division by zero at compile time). Then we can get the actual value by repeating the test with some other values. e.g
#include <stdio.h>
struct _X {
int a;
char c;
double d;
float f[30];
} X;
int r2=1/(sizeof(X)<140);
int r3=1/(sizeof(X)<137);
int r4=1/(sizeof(X)<136);
int r5=1/(sizeof(X)!=136);
int main()
{
return 0;
}
result
main.c:18:9: warning: division by zero [-Wdiv-by-zero]
int r4=1/(sizeof(X)<136);
^
main.c:18:8: error: initializer element is not constant
int r4=1/(sizeof(X)<136);
^
main.c:19:9: warning: division by zero [-Wdiv-by-zero]
int r5=1/(sizeof(X)!=136);
^
main.c:19:8: error: initializer element is not constant
int r5=1/(sizeof(X)!=136);
^
Hence we know sizeof(X)==136
.
Alternatively, by using the ?:
operator, we can make use of more C language constructs that are evaluated at compile time. Visual C++ example using array declaration:
#include "stdafx.h"
struct X {
int a;
char b[30];
double d;
float f[20];
};
int a1[sizeof(X)<130?-1:1];
int a2[sizeof(X)<120?1:-1];
int a3[sizeof(X)==128?-1:1];
int _tmain(int argc, _TCHAR* argv[]){
return 0;
}
result
1>------ Build started: Project: cpptest, Configuration: Release Win32 ------
1> cpptest.cpp
1>cpptest.cpp(11): error C2118: negative subscript
1>cpptest.cpp(12): error C2118: negative subscript
1>cpptest.cpp(13): error C2118: negative subscript
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
implying the sizeof(X)
is <130, not <120, and equals to 128
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.
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.