How Can This Structure Have Sizeof == 0

How can this structure have sizeof == 0?

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.

What is sizeof(something) == 0?

sizeof will never be zero. (Reason: sizeof (T) is the distance between elements in an array of type T[], and the elements are required to have unique addresses).

Maybe you can use templates to make a sizeof replacement, that normally uses sizeof but is specialized for one particular type to give zero.

e.g.

template <typename T>
struct jumpoffset_helper
{
enum { value = sizeof (T) };
};

template <>
struct jumpoffset_helper<Empty>
{
enum { value = 0 };
};

#define jumpoffset(T) (jumpoffset_helper<T>::value)

Can sizeof return 0 (zero)

In C++ an empty class or struct has a sizeof at least 1 by definition. From the C++ standard, 9/3 "Classes": "Complete objects and member subobjects of class type shall have nonzero size."

In C an empty struct is not permitted, except by extension (or a flaw in the compiler).

This is a consequence of the grammar (which requires that there be something inside the braces) along with this sentence from 6.7.2.1/7 "Structure and union specifiers": "If the struct-declaration-list contains no named members, the behavior is undefined".

If a zero-sized structure is permitted, then it's a language extension (or a flaw in the compiler). For example, in GCC the extension is documented in "Structures with No Members", which says:

GCC permits a C structure to have no members:

 struct empty {
};

The structure will have size zero. In C++, empty structures are part of the language. G++ treats empty structures as if they had a single member of type char.

Why this 'sizeof()' return is 0 bytes in C?

This code snippet

char vec[0];
vec[0] = 1;

invokes undefined behavior.

You may not declare an array with zero elements.

From the C Standard (6.7.6.2 Array declarators)

1 In addition to optional type qualifiers and the keyword static, the
[ and ] may delimit an expression or *. If they delimit an expression
(which specifies the size of an array), the expression shall have an
integer type. If the expression is a constant expression, it shall
have a value greater than zero.
The element type shall not be an
incomplete or function type. The optional type qualifiers and the
keyword static shall appear only in a declaration of a function
parameter with an array type, and then only in the outermost array
type derivation.

Pay attention to that there are used incorrect conversion specifiers in these calls of printf

printf("\n SIZEOF: %li", sizeof(vec));
printf("\n VEC[0]: %li", vec[0]);

For a value returned by the operator sizeof that has the type size_t you should use the conversion specifier %zu and for an object of the type char you should use the conversion specifier %c.

As for your question

Why "vec[0]" has a size of "0 bytes" even I adding value "vec[0] = 1"
? (If I don't add this value, just declare the vector "char vec[0] or
int vec[0]" the output is same).

then the compiler should issue a message relative to the invalid declaration of an array.

As for the output then as the array is not a variable length array then the value of the expression sizeof( vec ) is evaluated at compile time. The compiler sees that the number of elements is equal to 0 and it calculates the expression sizeof( vec ) as 0 * sizeof( char ). Thus this expression always yields 0 independent on the array element type.

Zero size struct

Neither struct declaration is allowed by the C standard. 6.7.2.1 (8) in n1570:

If the struct-declaration-list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined.

And paragraph 18 in the same section:

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.

(emphasis mine)

Flexible array members are not allowed in C++, so the code is not valid C++ either.

As it is not valid code, the values reported by sizeof for these are meaningless.

Why isn't sizeof for a struct equal to the sum of sizeof of each member?

This is because of padding added to satisfy alignment constraints. Data structure alignment impacts both performance and correctness of programs:

  • Mis-aligned access might be a hard error (often SIGBUS).
  • Mis-aligned access might be a soft error.

    • Either corrected in hardware, for a modest performance-degradation.
    • Or corrected by emulation in software, for a severe performance-degradation.
    • In addition, atomicity and other concurrency-guarantees might be broken, leading to subtle errors.

Here's an example using typical settings for an x86 processor (all used 32 and 64 bit modes):

struct X
{
short s; /* 2 bytes */
/* 2 padding bytes */
int i; /* 4 bytes */
char c; /* 1 byte */
/* 3 padding bytes */
};

struct Y
{
int i; /* 4 bytes */
char c; /* 1 byte */
/* 1 padding byte */
short s; /* 2 bytes */
};

struct Z
{
int i; /* 4 bytes */
short s; /* 2 bytes */
char c; /* 1 byte */
/* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */

One can minimize the size of structures by sorting members by alignment (sorting by size suffices for that in basic types) (like structure Z in the example above).

IMPORTANT NOTE: Both the C and C++ standards state that structure alignment is implementation-defined. Therefore each compiler may choose to align data differently, resulting in different and incompatible data layouts. For this reason, when dealing with libraries that will be used by different compilers, it is important to understand how the compilers align data. Some compilers have command-line settings and/or special #pragma statements to change the structure alignment settings.

The size of structure (sizeof) in C++ doesn't correspond the real size in case of arrays

Although a compiler can add packing to the end of a struct, a compiler absolutely cannot add additional packing between the elements when manufacturing an array.

For an array TestStructure[n], the address of the i(th) element must be TestStructure + i * sizeof TestStructure. If this were not true then pointer arithmetic would break horribly.

sizeof for a structure with char c[0]

Zero-length arrays are not in the standard C, but they are allowed by many compilers.

The idea is that they must be placed as the very last field in a struct, but they don't occupy any bytes. The struct works as a header for the array that is placed just next to it in memory.

For example:

struct Hdr
{
int a, b, c;
struct Foo foos[0]
};

struct Hdr *buffer = malloc(sizeof(struct Hdr) + 10*sizeof(Foo));
buffer->a = ...;
buffer->foos[0] = ...;
buffer->foos[9] = ...;

The standard way to do that is to create an array of size 1 and then substracting that 1 from the length of the array. But even that technique is controversial...

For more details and the similar flexible array member see this document.

sizeof initialized constant in c

Asking for the size of a structure with a flexible array member gives only the base size of the structure, without the array member. C 2018 6.7.2.1 18 says:

… In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply…

Thus, sizeof s is the size the structure would have if the flexible array member a were not present, except it may have extra padding. Since the uint32_t w; member requires four bytes, and your compiler does not insert extra padding in this case, the size of the structure is four bytes.

Note

The extra padding arises in cases like this:

struct foo
{
char c;
int array[];
};

In an implementation where int requires four-byte alignment, the compiler will ensure the array member is aligned by inserting three bytes after member c, so sizeof (struct foo) will be four.



Related Topics



Leave a reply



Submit