Anne Quinn
Anne Quinn

Reputation: 13040

Only one array without a size allowed per struct?

I was writing a struct to describe a constant value I needed, and noticed something strange.

namespace res{
    namespace font{
        struct Structure{
            struct Glyph{
                int x, y, width, height, easement, advance;
            };
            int glyphCount;
            unsigned char asciiMap[];   // <-- always generates an error
            Glyph glyphData[];          // <-- never generates an error
        };
        const Structure system = {95, 
                              {
                                 // mapping data
                              }, 
                              {
                                 // glyph spacing data
                              }
        }; // system constructor
    } // namespace font
} // namespace res

The last two members of Structure, the unsized arrays, do not stop the compiler if they are by themselves. But if they are both included in the struct's definition, it causes an error, saying the "type is incomplete"

This stops being a problem if I give the first array a size. Which isn't a problem in this case, but I'm still curious...

My question is, why can I have one unsized array in my struct, but two cause a problem?

Upvotes: 5

Views: 2820

Answers (5)

Mike Seymour
Mike Seymour

Reputation: 254751

In standard C++, you can't do this at all, although some compilers support it as an extension.

In C, every member of a struct needs to have a fixed position within the struct. This means that the last member can have an unknown size; but nothing can come after it, so there is no way to have more than one member of unknown size.

If you do take advantage of your compilers non-standard support for this hack in C++, then beware that things may go horribly wrong if any member of the struct is non-trivial. An object can only be "created" with a non-empty array at the end by allocating a block of raw memory and reinterpreting it as this type; if you do that, no constructors or destructors will be called.

Upvotes: 5

James Kanze
James Kanze

Reputation: 154047

Arrays without a dimension are not allowed in a struct, period, at least in C++. In C, the last member (and only the last) may be declared without a dimension, and some compilers allow this in C++, as an extension, but you shouldn't count on it (and in strict mode, they should at least complain about it). Other compilers have implemented the same semantics if the last element had a dimension of 0 (also an extension, requiring a diagnostic in strict mode).

The reason for limiting incomplete array types to the last element is simple: what would be the offset of any following elements? Even when it is the last element, there are restrictions to the use of the resulting struct: it cannot be a member of another struct or an array, for example, and sizeof ignores this last element.

Upvotes: 1

Sebastian Mach
Sebastian Mach

Reputation: 39109

You are using a non-standard microsoft extension. C11 (note: C, not C++) allows the last array in a structure to be unsized (read: a maximum of one arrays):

A Microsoft extension allows the last member of a C or C++ structure or class to be a variable-sized array. These are called unsized arrays. The unsized array at the end of the structure allows you to append a variable-sized string or other array, thus avoiding the run-time execution cost of a pointer dereference.

// unsized_arrays_in_structures1.cpp
// compile with: /c
struct PERSON {
   unsigned number;
   char name[];   // Unsized array
};

If you apply the sizeof operator to this structure, the ending array size is considered to be 0. The size of this structure is 2 bytes, which is the size of the unsigned member. To get the true size of a variable of type PERSON, you would need to obtain the array size separately.

The size of the structure is added to the size of the array to get the total size to be allocated. After allocation, the array is copied to the array member of the structure, as shown below:

Upvotes: 3

Synxis
Synxis

Reputation: 9388

It is an extension from Microsoft, and sizeof(structure) == sizeof(structure_without_variable_size_array).

I guess they use the initializer to find the size of the array. If you have two variable size arrays, you can't find it (equivalent to find one unique solution of a 2-unknown system with only 1 equation...)

Upvotes: 1

NPE
NPE

Reputation: 500923

The compiler needs to be able to decide on the offset of every member within the struct. That's why you're not allowed to place any further members after an unsized array. It follows from this that you can't have two unsized arrays in a struct.

Upvotes: 2

Related Questions