6

For example:

int main() {
  struct {} foo;
  int bar[0];
  struct {
    int dummy[0];
  } baz;
  cout << sizeof(foo) << endl; //display '1'
  cout << sizeof(bar) << endl; //display '0'
  cout << sizeof(baz) << endl; //display '0'
  return 0;
}

Please tell me is there any reason stand behind that compiler behaviour

DMaster
  • 603
  • 1
  • 10
  • 23
  • 8
    C++ doesn't even allow zero-size arrays. C does only when the size is not a constant expression. You should read your compiler's documentation for its behaviour in the second and third case because those are covered by the compiler extension, not the standard. – chris Jun 21 '15 at 06:01
  • Related: http://stackoverflow.com/questions/6180012/array-with-size-0 – juanchopanza Jun 21 '15 at 06:32
  • 4
    **Which language?** C and C++ are tremendously different. Especially in this regard. You can't expect a sensible answer for "C/C++". You either ask about C **xor** C++. – The Paramagnetic Croissant Jun 21 '15 at 06:51
  • @chris: Standard C doesn't allow zero size objects; neither zero element arrays nor structures nor unions with no members. GNU C does allow zero element arrays, though. They (Standard C and GNU C) are different, but closely related languages — there are a lot of extra things in GNU C that aren't part of standard C. – Jonathan Leffler Jun 21 '15 at 06:53
  • @JonathanLeffler, Ah, I missed a later paragraph of that section that went into VLAs in more detail. The size needs to be greater than zero every time it is evaluated in that case. Still doesn't change that the OP's case falls under the constant expression rule, but good to know. – chris Jun 21 '15 at 07:11
  • @TheParamagneticCroissant thank for asking me, I have deleted tag 'C' – DMaster Jun 21 '15 at 08:39

2 Answers2

12

This is a C++ only issue. In C, an empty struct is prohibited by the compiler.

In C++, the reason for the sizeof(foo) == 1 is ultimately so that the C++ Standard's rule of "no object shall have the same address in memory as any other variable" can be enforced. You can read the details here.

EDIT: Regarding the comment by user2864740 about baz appearing that it should also be non-zero is correct. The compiler is allowing the empty array which makes it appear that the finessing rule is not being applied consistently to baz like it was to foo. This does, in fact, mess up the pointer arithmetic. See this example:

// C++14 code
#include <iostream>
using namespace std;

int main() {
  struct baz {
    int dummy[1];
  };

  cout << sizeof(baz) << endl;

  baz* arr;
  arr = new baz[5];
  cout << &arr[0] << endl;
  cout << &arr[1] << endl;
  return 0;
}
// everything looks good
4
0x892c008
0x892c00c

But if we take the same code and change the array inside baz to be int dummy[0];, then we get this output:

0
0x8fe3008
0x8fe3008

Dangerous indeed; this could lead to infinite loops. It is recommended you don't be naughty like this even if you've found a way to get away with it :)

Special Sauce
  • 5,338
  • 2
  • 27
  • 31
  • I'm confused (after reading the article) because `baz` has 0 size. It seems like a the rules would also dictate it has a 1/non-zero size. (Unless going with the original code being .. a bad example.) – user2864740 Jun 21 '15 at 06:00
  • 2
    @user2864740 That is because your code isn't standards conforming C++. You can't have length zero arrays like that. *Edit*: It seems it is a gcc extension, so you can either not use it or read up in the gcc manual how it is supposed to work. – juanchopanza Jun 21 '15 at 06:29
  • I wouldn't say the OP tricked the compiler. I would be shocked if the behaviour wasn't specified in the compiler docs. – chris Jun 21 '15 at 06:32
  • Thank you for "It could lead to infinite loops". However, I often use an object like `baz` as a function (I define an `inline result_t operator()(...)` to use, and declare only one object for this class, because I think this is far more efficient than function pointer), and I rarely (perhaps never) do an iterating loop for that. I think if an empty class (without any member, not even empty array) have size of 1, it may wasting some in memory. I also want to know if any class in C++ must have non-zero size, why `baz` ...? Is `baz`-form class an except? – DMaster Jun 21 '15 at 09:08
  • @DMaster C/C++ have long been languages that expert programmers turn to when they feel overly confined or slowed down in more restrictive languages. You are welcome to use the language however you like as long as it compiles and you are willing to own the results. – Special Sauce Jun 21 '15 at 09:29
  • @DMaster Regarding the second part of your comment, it appears to me that `baz` is being exempted from the empty class -> `sizeof() == 1` rule because the empty array inside the struct is enough to throw the compiler off track from applying that finessing rule. I personally would not have made the finessing rule to start with seeing that it isn't being applied consistently and there are some dangers to fake `sizeof()` as well. But then again, I'm not one of these beautiful people (https://isocpp.org/std/the-committee). – Special Sauce Jun 21 '15 at 09:31
  • @MattMcNabb But we can't create an object from an abstract class. And if want to do `baz()`, `baz` must be an object first. – DMaster Jun 21 '15 at 09:34
2

Edit: Assuming g++

sizeof returns the size of object in bytes http://en.cppreference.com/w/cpp/language/sizeof

The size of an empty array is 0, because there are no bytes in it. The size of struct, in general is not zero. If the compiler figures out that the struct is empty, then it will report a zero.

In your case, the compiler can tell that the number of bytes in the struct is zero. Hence, sizeof(bar) and sizeof(baz) is zero

See here also http://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#The-sizeof-Operator

bendervader
  • 2,619
  • 2
  • 19
  • 22