开发者

Why is zero-length array allowed only if it's heap allocated?

开发者 https://www.devze.com 2023-03-23 19:29 出处:网络
I notice that it\'s not allowed to create开发者_JS百科 non-heap allocated arrays of zero length.

I notice that it's not allowed to create开发者_JS百科 non-heap allocated arrays of zero length.

// error: cannot allocate an array of constant length zero
char a[0];

I also notice that it's allowed to create heap allocated arrays of zero length.

// this is okay though
char *pa = new char[0];

I guess they're both guaranteed by the Standard (I don't have a copy of the Standard at hand). If so, why are they so different? Why not just allow a zero-length array on stack (or vice versa)?


This is addressed in the following Sections of the C++ Standard.

3.7.3.1/2:

[32. The intent is to have operator new() implementable by calling malloc() or calloc(), so the rules are substantially the same. C++ differs from C in requiring a zero request to return a non-null pointer.]

And also,

5.3.4, paragraph 7

When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.


An Array of size 0 is not allowed by the C++ standard:

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."

In my understanding the rationale behind this seems to be the fact that C++ standard requires that every object must have an unique address(this is the very reason even an empty class object has size of 1).In the case of a non heap zero sized array, no objects need to be created, and hence no address is required to be given to it and hence no need of allowing it in first place.


As far as c is concerned, zero length arrays are allowed by the c standard, typically they are used to implement structures having a variable size by placing the zero length array at the end of the structure. If my memory serves my correct it is popularly called as C struct Hack.


A 0 length array isn't very useful. When you're calculating the dimension, it can occur, and it is useful to not have to treat the case specially in your code. Outside of new, the dimension of the array must be a constant, not a calculated value, and if you know that the constant is 0, why define it?

At least, that's the rationale I've heard (from people who worked on it). I'm not totally convinced: it's not unusual in code to have to work with symbolic constants whose value isn't known (from a header file, or even the command line). So it probably would make sense to allows arrays of 0 elements. And at least one compiler in the past has allowed them, although I've forgotten which.

One frequent trick in C++ is to use such an array in a compile time assert, something like:

char dummyToTestSomeSpecificCondition[ condition ];

This will fail to compile if the condition is false, and will compile if it isn't. Except for that one compiler (if it still exists); I'll use something like:

char dummyToTestSomeSpecificCondition[ 2 * condition - 1 ];

, just in case.


I think that the main reason why they behave different is that the first one:

char a[0];

is an array of size 0, and this is forbidden because its size should be by definition 0*sizeof(char), and in C or C++ you cannot define types of size 0.

But the second one:

char *pa = new char[0];

is not a real array, it is just a chunk of 0 objects of type char put all together in memory. Since a sequence of 0 objects may be useful, this is allowed. It just return a pointer past the last item, and that is perfectly fine.

To add to my argument, consider the following examples:

new int[0][3]; //ok: create 0 arrays of 3 integers
new int[3][0]; //error: create 3 arrays of 0 integers

Although both lines would alloc the same memory (0 bytes), one is allowed and the other is not.


That depends on compiler implementation/flags. Visual C++ doesn't allow, GCC allows (don't know how to disable). Using this approach, STATIC_ASSERT may be implemented in VC, but not in GCC:

#define STATIC_ASSERT(_cond) { char __dummy[_cond];}


Even intuitively this makes sense.

Since the heap allocated method creates a pointer on the stack, to a piece of memory allocated on the heap, it's still "creating something" of size: sizeof(void*). In the case of allocating a zero length array, the pointer that exists on the stack can point anywhere, but nowhere meaningful.

By contrast, if you allocate the array on the stack, what would a meaningful zero length array object look like? It doesn't really make sense.

0

精彩评论

暂无评论...
验证码 换一张
取 消