Can Sizeof Return 0 (Zero)

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.

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 a class or object ever be zero?

It's called "flexible array member" and it's a feature of C99 (I think). It's not valid C++ - you don't have warnings/errors, probably because the compiler supports it as an extension.

Compiling with -Wall -Wextra -pedantic -std=c++NN (98, 03, 11, 14, ..) should generate warning (the last two flags will disable any compiler extensions).


You can see some information in this related question: Is using flexible array members in C bad practice?

For example, here's what GCC says about this:

In ISO C99, you would use a flexible array member, which is slightly different in syntax and semantics:

...

Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero.

(source: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html).

This explains the 0 size of char a[] and not the 0 for the class, but as I already mentioned - it's a C feature and not a valid C++.

Is there any chance the sizeof operator returns 0?

Objects in C always have a positive size, so no sizeof can never lead to 0.

C doesn't allow empty struct or union types and also arrays must have a size that is bigger than 0. So there is no correct C type what soever that can return a value of 0.

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.

Why do I get warning C4034: sizeof returns 0?

You must move the size computation to the file that actually defines the array, Data.c:

#include "Data.h"

struct NUMBERS Hello[] = {
{11, 12, 13, 14},
{15, 16, 17, 18},
{19, 20, 21, 22},
{23, 24, 25, 26}
};
int SizeOfHello = sizeof Hello/sizeof(struct NUMBERS);

It would be written more reliably this way:

int SizeOfHello = sizeof(Hello) / sizeof(*Hello);

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.

Objects of size 0

Code not valid.

A size of 0 is invalid, both for classes and arrays. The C++ standard says:

Sizeof [expr.sizeof]


[...] The size of a most derived class shall be greater than zero [...]

and

Arrays [dcl.array]


In a declaration T D where D has the form

    D1 [ constant-expressionopt] attribute-specifier-seqopt

[...] If the constant-expression (5.19) is present,
it shall be an integral constant expression and its value shall be greater than zero [...]


Why compiles? Compiler extension!

If you turn on -pedantic with g++, you will receive the following warning (or error with pedantic-errors):

ISO C++ forbids zero-size array ‘n’

so your program is basically not valid, but can be compiled by means of a compiler extension to the C++ standard (unless you turn this extension off).

Note: Even though your compiler can report 0 for the class, it won't do so for any instance (a.k.a. object) of that class:

#include <iostream>
class Boom {
int n[0];
};
int main() {
std::cout << sizeof(Boom) << '\n'; // prints 0
std::cout << sizeof(Boom()) << '\n'; // prints 1
}

Having objects of size-0 would go simply too far off the standard.

Citation by Stroustroup:

Why is the size of an empty class not zero?


To ensure that the addresses of two different objects will be different. For the same reason, "new" always returns pointers to distinct objects. Consider:

class Empty { };

void f()
{
Empty a, b;
if (&a == &b) cout << "impossible: report error to compiler supplier";
Empty* p1 = new Empty;
Empty* p2 = new Empty;
if (p1 == p2) cout << "impossible: report error to compiler supplier";
}

There is an interesting rule that says that an empty base class need not be represented by a separate byte:

   struct X : Empty {
int a;
// ...
};

void f(X* p)
{
void* p1 = p;
void* p2 = &p->a;
if (p1 == p2) cout << "nice: good optimizer";
}

This optimization is safe and can be most useful. It allows a programmer to use empty classes to represent very simple concepts without overhead. Some current compilers provide this "empty base class optimization".

function returning zero sized string even when its size is not zero

As I mentioned in the comments, the size of your string, s, is always zero since you are never actually changing its size. The size of a string can change in a few ways, through assignment (=, +=), and resize being two. Your program currently has undefined behaviour, since, when you do s[f]=A[i][f], you are modifying s at index f, even though s has no contents.

So how do you fix this? Initially, you can resize s to the size of m, and fill it temporarily with spaces. Now, there's still a logic problem in your if statement. Specifically, with the else, since if the else is reached, you need to cut off anything remaining, and change m. See the below for a full working program:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

string longestCommonPrefix( const vector<string> &A ) {
string s;
int k = A.size();
int m = A[0].size();
for ( int i = 1; i < k; i++ ) {
int j = A[i].size();
if ( j < m ) m = j;
}
int f;
s.resize( m, ' ' ); // temporary, just to set the contents
for ( int i = 0; i < k - 1; i++ ) {
for ( f = 0; f < m; f++ ) {
if ( A[i][f] == A[i + 1][f] ) {
s[f] = A[i][f]; // copy the similar values
} else {
m = f; // if we reach a character which is not the same, then we reset m
s.resize( m ); // and resize the string
}
}
}
return s;
}

int main() {
vector<string> a;
a.push_back( "hello" );
a.push_back( "hell" );
a.push_back( "help" );
a.push_back( "he" );
cout << longestCommonPrefix( a );
getchar();
}

The above will have an output of he, which is the common prefix of all three words.

The below is a modified version of the function. First, I've replaced int with size_t, which should be used for any sizes. Second, it introduces a few error checks and simplifications. If the input vector is size 0, then don't do any checks and return an empty string. If the size is 1, then just return the contents of the element. No work needed.

After this, assume that A[0] is the entire prefix which belongs to all elements in the vector. In the for loop, you would then look for when this is not true, and resize the string accordingly. You will notice that the loop starts at 1, since we are assuming the first element is the full prefix. The inner loop also is less than s.size(), so that as s shrinks, it is accounted for.

string longestCommonPrefix( const vector<string> &A ) {
size_t k = A.size();
if ( k == 0 )
return "";
if ( k == 1 )
return A[0];

string s = A[0];
for ( size_t i = 1; i < k - 1; i++ ) {
if ( A[i].size() < s.size() ) s.resize( A[i].size() );
for ( size_t f = 0; f < s.size(); f++ ) {
if ( A[i][f] != A[i + 1][f] ) {
s.resize( f );
}
}
}
return s;
}

EDIT: There was an issue in the second version, with going out of bounds. UB again (oops). I added in a check, inside the first for loop, which now resizes s if it is larger than A[i]



Related Topics



Leave a reply



Submit