3

Given example class

class test
{
public:
test();
~test();
void someMethod();
void someOtherMethod();

private:
int var;
};

is sizeof(test) == sizeof(int), or we cannot make such assumption? Is it platform/compiler dependent?

EDIT:

Motivation for that is to read/write class through stream. Class indeed contains a single integer, with some convenience access methods - highest order byte of integer is reserved for flags, 3 lower bytes represent integer 24 bit number. Given this, idea is to write arrays of such class variables, and read them as plain int if needed. The question quoted as having possible answer doesn't address that aspect - is more about padding with multiple elements.

Ilya Kobelevskiy
  • 5,245
  • 4
  • 24
  • 41
  • Though I doubt any compiler would put padding in there, it could. – chris Jul 11 '13 at 16:21
  • 3
    Note that your class has no virtual functions and no virtual base classes etc. That simplifies it. If your class had any virtuals, you can be fairly confident that the size will be bigger than `sizeof(int)` (though that is not guaranteed by the standard). As it stands, it is likely that `sizeof(test) == sizeof(int)`, but that is certainly not guaranteed by the standard (a compiler could make it larger; it probably can't make it smaller). – Jonathan Leffler Jul 11 '13 at 16:30
  • I have to point out that unless you are moving data in to or out of your program, you generally should not care that the sizes of your classes are not the same as the sizes of the members. This is a micro-concern. Unless you can **prove** that the size of a class is a specific bottleneck in your code, taking steps to make sure it has a specific size is a premature micro-optimization. One that could have negative impact, at that. – John Dibling Jul 11 '13 at 16:50
  • @John Dibling Yes, the motivation for that is to read/write the whole class through stream like stream.write((char*)classVar,sizeof(test)); – Ilya Kobelevskiy Jul 11 '13 at 16:52
  • @IlyaKobelevskiy: Ok, that is a legitimate reason. Be aware of endianness when doing so. – John Dibling Jul 11 '13 at 16:54

2 Answers2

7

In general, no you cannot assume that the size of some arbitrary class is simply the aggregation of the size of it's members. In general, nor should you care*. The compiler can and will change the size of your classes so that their size is is a multiple of some specific number of bytes. The reason it does this is to improve performance. What that number of bytes is is different for every platform.

In this specific example, it might in fact be the case that sizeof (test) == sizeof (int), but I doubt this is the real code that prompted this question.

There are ways you can ensure that it does, but they rely on platform-specific functionality.

First, made sure your class is a POD* and all the members are themselves PODs.

Second, set the packing to 1 byte. Under both GCC and MSVC, the instruction to do this is similar to:

#pragma pack (1)

You should turn this packing off when it is not strictly needed, as it could have a negative impact on performance:

#pragma pack (push, 1)

class test
{
public:
  void someMethod();
  void someOtherMethod();

  int var;
};

#pragma pack (pop)

Note that above I removed the private section. You class is not a POD if it has nonstatic private or protected data members. I also removed the default constructor and destructor for the same reason.

Under both MSVC and GCC, sizeof(test) will equal sizeof(int).


POD: Plain Old Datatype. In order for a class (or struct) to be a POD, it must have no user-defined destructor or constructor, copy-assignment operator, and no non-static members of type pointer to member. In addition, it must have no virtuals, no private or protected non-static members and no base classes. Moreover, any nonstatic data members it does have must also be PODs themselves. In other words, just plain old (public) data.


"Nor should you care." In general, the only times you need to make sure the size of some class is exactly the size of the members is at the boundaries of the system. For example, when moving data in to or out of your program via a socket. The compiler pads your classes for a reason. You should not override the compiler in this unless you have a specific, provable cause.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 1
    `static_assert(sizeof(test) == sizeof(int))` is going to be a big help here. – Cory Nelson Jul 11 '13 at 17:04
  • Thanks a lot for this very detailed answer. Even without alignment enforcement sizes match on msvc. I will go with no alignment enforcement but static_assert approach that Cory Nelson suggested - as long as problems can be detected compile time, it is safe. – Ilya Kobelevskiy Jul 11 '13 at 17:09
  • BTW *POD* isn't necessary, only *standard-layout*. – Ben Voigt Jun 20 '14 at 00:35
6

You can not make that assumption.

The compiler is allowed to add padding to improve performance. Maybe your target system can only read 64 bit values. Reading smaller values requires reading 64 bits and then masking to 32 bits. On such a system it would be more efficient to just pad the class out to 64 bits.

If you really need a class or struct to be the exact size that you request, almost every compiler has attributes or pragmas to control the padding.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131