Is it possible to determine the size of a C++ class at compile-time?
I seem to remember a template meta-programming method, but I could be mistaken...
开发者_如何转开发sorry for not being clearer - I want the size to be printed in the build output window
If you really need to to get sizeof(X) in the compiler output, you can use it as a parameter for an incomplete template type:
template<int s> struct Wow;
struct foo {
int a,b;
};
Wow<sizeof(foo)> wow;
$ g++ -c test.cpp
test.cpp:5: error: aggregate ‘Wow<8> wow’ has incomplete type and cannot be defined
To answer the updated question -- this may be overkill, but it will print out the sizes of your classes at compile time. There is an undocumented command-line switch in the Visual C++ compiler which will display the complete layouts of classes, including their sizes:
That switch is /d1reportSingleClassLayoutXXX, where XXX performs substring matches against the class name.
https://devblogs.microsoft.com/cppblog/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022/
EDITED (3jun2020) This trick works IN ALL C COMPILERS. For Visual C++:
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 ==========
For other compilers that only print "duplicate case value", see my answer to this question: How can I print the result of sizeof() at compile time in C?
Whats wrong with sizeof
? This should work on objects and classes.
void foo( bar* b )
{
int i = sizeof bar;
int j = sizeof *b;
// please remember, that not always i==j !!!
}
Edit:
This is the example I was thinking of, but for some reason it's not working. Can anyone tell me what's wrong?
#include <iostream>
using namespace std;
class bar {
public: int i;
bar( int ii ) { i = ii; }
virtual ~bar(){ i = 0; }
virtual void d() = 0;
};
class bar2: public bar {
public: long long j;
bar2( int ii, long long jj ):bar(ii){ j=jj; }
~bar2() { j = 0; }
virtual void d() { cout << "virtual" << endl; };
};
void foo( bar *b )
{
int i = sizeof (bar);
int j = sizeof *b;
cout << "Size of bar = " << i << endl;
cout << "Size of *b = " << j << endl;
b->d();
}
int main( int arcc, char *argv[] )
{
bar2 *b = new bar2( 100, 200 );
foo( b );
delete b;
return 0;
}
The application been run on linux (gcc 4.4.2):
[elcuco@pinky ~/tmp] ./sizeof_test
Size of bar = 8
Size of *b = 8
virtual
This macro is based off grep's answer. Define the macro like below:
#define COMPILE_TIME_SIZEOF(t) template<int s> struct SIZEOF_ ## t ## _IS; \
struct foo { \
int a,b; \
}; \
SIZEOF_ ## t ## _IS<sizeof(t)> SIZEOF_ ## t ## _IS;
Then use it like this:
COMPILE_TIME_SIZEOF(long);
And you'll get an output similar to below:
error: 'SIZEOF_long_IS<4> SIZEOF_long_IS' redeclared as different kind of symbol
SIZEOF_ ## t ## _IS<sizeof(t)> SIZEOF_ ## t ## _IS;
Still a bit of a workaround, but easy enough to use.
sizeof() determines the size at compile time.
It doesn't work until compile time, so you can't use it with the preprocessor.
Compile-time sizeof as a Warning so Compilation can Continue
Here is a version which produces a warning rather than an error:
/** Compile-time sizeof as a warning so
compilation can continue */
struct TestStruct
{
int i1;
float f1;
const char* pchar1;
double d1;
char c1;
void* pv1;
bool b1;
};
template<unsigned int n>
struct PrintNum {
enum { value = n };
};
template<int number>
struct _{ operator char() { return number + 256; } };
#define PRINT_AS_WARNING(constant) char(_<constant>())
int main()
{
PRINT_AS_WARNING(PrintNum<sizeof(TestStruct)>::value);
return 0;
}
See it running on Godbolt. As an aside, you can read the size(48
) right out of the assembly there:
leaq -1(%rbp), %rax
movq %rax, %rdi
call _<48>::operator char()
movl $0, %eax
leave
ret
There is operator sizeof( int )
, sizeof( char )
so I think that it is possible and call probably look like sizeof( MyClass )
Yet, another trick causing the VC++2010 compiler to complain about incorrect use of compile time integer:
// cpptest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
struct X {
int a[11];
char c[2];
};
void proc1(void* s[1]) {
}
int _tmain(int argc, _TCHAR* argv[])
{
int b[sizeof(X)];
proc1(b);
return 0;
}
1>------ Build started: Project: cpptest, Configuration: Release Win32 ------ 1> cpptest.cpp 1>cpptest.cpp(14): error C2664: 'proc1' : cannot convert parameter 1 from 'int [48]' to 'void *[]' 1>
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Hence sizeof (struct X) is 48. This also works for C code.
This is the snippet, that I use:
template <typename T>
void get_sizeof() {
switch (*((int*)0x1234)) { case sizeof(T): case sizeof(T):; }
}
To get the size, instantiate the function anywhere in the code, for example, within a statement:
struct S { long long int ill; };
get_sizeof<S>;
The error will look like:
error: duplicate case value '8'
switch (*((int*)0x1234)) { case sizeof(T): case sizeof(T):; }
^
I developed a tool, named compile-time printer, to output values and types during compilation.
You can try it online under: https://viatorus.github.io/compile-time-printer/
The repository can be found here: https://github.com/Viatorus/compile-time-printer
To get the size of any type as output would be:
constexpr auto unused = ctp::print(sizeof(YourType));
In g++ one can use option "-fdump-lang-class". Then g++ creates a new output file with extension .class, which contains the sizes of all classes defined in the compiled unit.
精彩评论