66

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

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Tim Gradwell
  • 2,312
  • 5
  • 24
  • 25
  • Of course - sizeof(C) where C is the class. Printing it is your problem. –  Jan 05 '10 at 21:31

12 Answers12

143

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
Maxim Razin
  • 9,114
  • 7
  • 34
  • 33
  • 3
    And if you don't want an error, but merely a warning, use it as the template parameter for a complete type, and subsequently define an otherwise unused object of that type. I.e. `Wow unused_warning;`. – MSalters Jan 06 '10 at 09:43
  • For VS2010, don't forget to look at the 'Output' window, because the 'Error List' only contains a condensed message that doesn't show the size value. – Coder_Dan Sep 13 '12 at 13:38
  • 1
    Also don't be fooled by VS2010's IntelliSense, which can report a different number that shown by cl. – chappjc Mar 20 '14 at 00:05
  • Note: I had to define a local variable to observe any useful message on gcc4.6. In other words, I had no luck with member variables. – Luc Hermitte Aug 22 '14 at 13:01
  • `error: use of undeclared identifier 'wow'; did you mean 'pow'?` No but thanks anyway, clang. – screwnut Oct 24 '22 at 15:24
13

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/

CyberTech
  • 56
  • 2
  • 7
aalpern
  • 652
  • 4
  • 8
  • 1
    Of course, I should have said that only applies to Visual C++, since the original question didn't specify a platform. I only work on Windows these days, hence my bias. – aalpern Jan 05 '10 at 19:49
  • Would be interesting to know which versions of the compiler support this switch. – Andreas Haferburg Feb 20 '16 at 16:53
6

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;
}

Example output:

------ 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?

Craig McQueen
  • 41,871
  • 30
  • 130
  • 181
JavaMan
  • 4,954
  • 4
  • 41
  • 69
  • I got a different error code, where the compiler (avrgcc) did not replace the sizeof() expression with its value. The workaround is to write once sizeof(dummy) and then provide other cases (like 1, 2, 4, 8, etc). This works for simple types but it's going to be painful to implement with something more complex, like a struct or a class. – Igor Stoppa Jun 07 '16 at 19:42
  • I have added another answer illustrating another C code compatible trick. Not sure if it works for your compiler or not – JavaMan Aug 11 '16 at 07:31
  • just try different ways of using a compile time integer incorrectly and replace that integer with sizeof() which is evaluated at compile time, too – JavaMan Aug 11 '16 at 07:34
  • GCC 5 does not print the value though. Just says "duplicate case value". – rustyx Sep 11 '16 at 20:48
  • see my edit for gcc or any other compilers that only print "duplicate case value" – JavaMan Jun 03 '20 at 09:06
4

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
elcuco
  • 8,948
  • 9
  • 47
  • 69
  • @elcuco - the second line should be `sizeof(*b)` – R Samuel Klatchko Jan 05 '10 at 19:08
  • @R Samuel: Or just `sizeof *b`. `sizeof` is an operator not requiring brackets, except that type names have to be surrounded by brackets, similar to casting syntax. – C. K. Young Jan 05 '10 at 19:11
  • 5
    When would i!=j? `sizeof` calculates at compile time, and all that's known is the type of the argument - in both cases this is `bar`. If you have a child class of `bar` that is larger, and you pass a pointer to an instance of the child into this function, you still just get the size of `bar` - polymorphism doesn't work at this level. – Mark Ransom Jan 05 '10 at 19:32
  • That's a good point. You need a virtual method in the derived classes to return their own size. – Nathan Osman Jan 05 '10 at 19:57
  • Sorry, I was not talking about your code, just the above question. – Nathan Osman Jan 05 '10 at 20:38
  • @elcuco: (Re revision comment.) So, who's the n00b again? This is a perfectly valid C program: `int main(int argc, char** argv) {return sizeof *argv;}`. Trust me, `sizeof` needs no brackets when referring to expressions (as opposed to type names). – C. K. Young Jan 05 '10 at 20:46
  • 1
    Aside: Seeing `sizeof` used "as a function" is a serious peeve of mine. It's not a function; it's an operator. If you declare `int i`, both `sizeof i` and `sizeof (int)` should yield identical results. (I make a point to put a space after `sizeof` so nobody thinks it's a function, just as I do after `if`, `while`, or `for`.) – C. K. Young Jan 05 '10 at 20:51
  • `int i = sizeof bar;` should be `size_t i = sizeof(bar);`. As everyone knows, parentheses are needed when the operand of `sizeof` is a type. And `sizeof` operator yields a value of `size_t` type. – Alok Singhal Jan 09 '10 at 23:08
3

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.

MattCochrane
  • 2,900
  • 2
  • 25
  • 35
2

sizeof() determines the size at compile time.

It doesn't work until compile time, so you can't use it with the preprocessor.

R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
1

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
ahcox
  • 9,349
  • 5
  • 33
  • 38
0

There is operator sizeof( int ), sizeof( char ) so I think that it is possible and call probably look like sizeof( MyClass )

Gaim
  • 6,734
  • 4
  • 38
  • 58
  • 1
    `sizeof` is an operator, not a function. You can't take the address of `sizeof` (whereas you can take the address of functions). :-P – C. K. Young Jan 05 '10 at 19:09
0

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.

JavaMan
  • 4,954
  • 4
  • 41
  • 69
0

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):; }
                                                ^
tonso
  • 1,760
  • 1
  • 11
  • 19
0

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));
Viatorus
  • 1,804
  • 1
  • 18
  • 41
0

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.