How can this structure have sizeof == 0?

There is an old post asking for a construct for which sizeof would return 0. There are some high score answers from high reputation users saying that by the standard no type or variable can have sizeof 0. And I agree 100% with that.

However there is this new answer which presents this solution:

struct ZeroMemory {
int *a[0];
};

I was just about to down-vote and comment on it, but time spent here taught me to check even the things that I am 100% sure on. So... to my surprise both gcc and clang show the same results: sizeof(ZeroMemory) == 0. Even more, sizeof a variable is 0:

ZeroMemory z{};
static_assert(sizeof(z) == 0); // Awkward...

Whaaaat...?

Godbolt link

How is this possible?

6399 次浏览

As pointed out by Jarod42 zero size arrays are not standard C++, but GCC and Clang extensions.

Adding -pedantic produces this warning:

5 : <source>:5:12: warning: zero size arrays are an extension [-Wzero-length-array]
int *a[0];
^

I always forget that std=c++XX (instead of std=gnu++XX) doesn't disable all extensions.

This still doesn't explain the sizeof behavior. But at least we know it's not standard...

In C++, a zero-size array is illegal.

ISO/IEC 14882:2003 8.3.4/1:

[..] If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero. The constant expression specifies the bound of (number of elements in) the array. If the value of the constant expression is N, the array has N elements numbered 0 to N-1, and the type of the identifier of D is “derived-declarator-type-list array of N T”. [..]

g++ requires the -pedantic flag to give a warning on a zero-sized array.

Zero length arrays are an extension by GCC and Clang. Applying sizeof to zero-length arrays evaluates to zero.

A C++ class (empty) can't have size 0, but note that the class ZeroMemory is not empty. It has a named member with size 0 and applying sizeof will return zero.

Before C was standardized, many compilers would have had no difficulty handling zero-size types as long as code never tried to subtract one pointer to a zero-size type from another. Such types were useful, and supporting them was easier and cheaper than forbidding them. Other compilers decided to forbid such types, however, and some static-assertion code may have relied upon the fact that they would squawk if code tried to create a zero-sized array. The authors of the Standard were faced with a choice:

  1. Allow compilers to silently accept zero-sized array declarations, even in cases where the purpose of such declarations would be to trigger a diagnostic and abort compilation, and require that all compilers accept such declarations (though not necessarily silently) as producing zero- sized objects.

  2. Allow compilers to silently accept zero-sized array declarations, even in cases where the purpose of such declarations would be to trigger a diagnostic and abort compilation, and allow compilers encountering such declarations to either abort compilation or continue it at their leisure.

  3. Require that implementations issue a diagnostic if code declares a zero-sized array, but then allow implementations to either abort compilation or continue it (with whatever semantics they see fit) at their leisure.

The authors of the Standard opted for #3. Consequently, zero-sized array declarations are regarded by the Standard "extension", even though such constructs were widely supported before the Standard forbade them.

The C++ Standard allows for the existence of empty objects, but in an effort to allow the addresses of empty objects to be usable as tokens it mandates that they have a minimum size of 1. For an object that has no members to have a size of 0 would thus violate the Standard. If an object contains zero-sized members, however, the C++ Standard imposes no requirements about how it is processed beyond the fact that a program containing such a declaration must trigger a diagnostic. Since most code that uses such declarations expects the resulting objects to have a size of zero, the most useful behavior for compilers receiving such code is to treat them that way.