简体   繁体   中英

Can “sizeof” a class or object ever be zero?

We all know that sizeof an empty class or an object of empty class will be 1 byte. I came across something where sizeof a class and its object is coming as 0. The program is syntactically correct as there were no compilation or run time errors. Is this undefined behavior? The use case I'm trying to execute makes any sense and looks like a valid one? Is it a big blunder to not to give exact subscript or size for an array in the class? The code snippet is as below:

#include<iostream>
using namespace std;
class A
{
   char a[];
};
int main()
{
    A b;
    cout<<sizeof(A)<<endl;
    cout<<sizeof(b)<<endl;
    return 0;
}

output:

0

0

The sizeof an empty class is one byte (non zero basically) and the reason for that is said like "To make sure that different objects have different addresses".

What happens in this case then when sizeof class is coming a zero? Note: Observed the same behavior for int a[] as well.

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

If you compile with -pedantic flag

$ g++ -W -Wall -pedantic prog.cpp
prog.cpp:5:11: warning: ISO C++ forbids zero-size array 'a' [-pedantic]

C++ does not support VLA s and thus your class declaration is not legal and going outside the scope of standard C++ rules.

Your code is not standard C++, thus I can not see any sense in that.

If you use pedantic flag, you should receive this:

gsamaras@pythagoras:~$ g++ -pedantic file.cpp
file.cpp:5:11: warning: ISO C++ forbids zero-size array ‘a’ [-Wpedantic]
    char a[];
         ^

Try changing your class to

class A {
   char a[5];
};

then you should get an output of

5
5

like you should expect.

However, you can argue that without the flag, your code does compile and outputs zeroes. As a counter I could say that the same goes if you use this class:

class A {
   char a[0];
};

but I am pretty sure you know that zero-sized arrays are not allowed, but still this thing compiles fine and gives an output of zeroes.

Empty base classes can be optimized to zero bytes, which would technically make sizeof(base) also 0 .

The "1 byte" thing is really an implementation detail, coming from the rule that distinct objects need to have distinct addresses.

So:

struct base { };

struct derived : base { };

Both sizeof(base) and sizeof(derived) are allowed to be 0 , because the derived object is the same object as the base object contained within.

However:

struct base1 { };
struct base2 { };
struct derived : base1, base2 { };

Here, sizeof(derived) must be 1, because the standard requires that

derived d;
assert(static_cast<base1 *>(&d) != static_cast<base2 *>(&d));

Similarly:

struct type1 { };
struct type2 { };
struct combined { type1 obj1; type2 obj2; };

requires that

combined c;
assert(&c.obj1 != &c.obj2);

Many compiler vendors take the shortcut and simply make empty classes take up one byte.

The size of a class can be 0. Consider the following piece of code

#include <iostream>
using namespace std;

class A
{
    public:
    int a[0];
    void getA(){
        cout<<"Hello World";
    }
};

class B
{
};

int main()
{
    cout<<"The size of A is "<<sizeof(A)<<endl;   // prints 0
    A w;
    cout<<"The size of object of A is "<<sizeof(w)<<endl;    //prints 0
    cout<<"The size of the array a in A is "<<sizeof(w.a)<<endl;  // prints 0
    cout<<"The value from function of class A is  "<<w.getA()<<endl;  // Gives a compilation error
    cout<<"The size of B is "<<sizeof(B)<<endl;  //prints 1
}


Output:
The size of A is 0
The size of object of A is 0
The size of the array a in A is 0
The size of B is 1

So, accessing functions present in the class with a size 0 leads to compilation error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM