How to correctly fix “zero-sized array in struct/union” warning (C4200) without breaking the code?

后端 未结 6 1392
北海茫月
北海茫月 2021-02-05 07:52

I\'m integrating some code into my library. It is a complex data structure well optimized for speed, so i\'m trying not to modify it too much. The integration process goes well

6条回答
  •  青春惊慌失措
    2021-02-05 08:08

    The main idea for this in C is to get for _TREEDATSTR elements the needed extra memory; in other words allocation will be done with malloc(sizeof(_TREEDATSTR) + len).

    Pragma pack is used to ask the compiler to leave no empty spaces between the fields (normally compilers do sometimes leave some unused bytes between fields of structres to guarantee alignment because in many modern processors this is a huge speed improvement).

    Note however that there are architectures where unaligned access is not just slow... but totally forbidden (segfault) so those compilers are free to ignore the pragma pack; code that uses pragma pack is inherently unportable.

    I think I would have put the dword first in the structure, and this probably wouldn't have required a pragma pack; also a way to silence the warning is to allocate a one element array and doing the allocation using (len-1) extra bytes.

    In C++ all this stuff is quite dangerous, because you're basically fooling the compiler into thinking that the size of the object is smaller than it really is, and given that C++ is a copy-logic language this means asking for troubles (for example for copy construction and assignment functions that will act only on the first part of the object). For everyday use it's surely MUCH better to use for example an std::vector instead, but this of course will come at an higher price (double indirection, more memory for every _TREEDATSTR instance).

    I normally don't like thinking all other programmers are idiots, so if this kind of bad trickery has been used then probably there is a well paying reason for it... For a definitive judgment however a much deeper inspection would be needed.

    To summarize:

    1. Using a zero element array at the end of an array is a trick used to create variable-sized objects. The allocation is done by requesting sizeof(structure) + n*sizeof(array_element) bytes.
    2. Pragma pack is used to tell the compiler to avoid adding extra padding bytes between structure fields. This is needed when a precise control on the memory layout is needed (for example because those object are being accessed by hand-written assembly)
    3. Don't do that in C++ unless you really need it and you know what you're doing

    There is no way to "correctly" silence the warning because the code wants to play dirty (and C++ compilers don't like to be fooled about object size). If you use this object inside other objects, or as a base for other objects, or pass it aroud by value then whatever bad happens you asked for it.

提交回复
热议问题