I am getting the sizeof of object as zero, which is ought not to be. Please explain me the concept as why the compiler is giving this answer?
#include<iostream>
using namespace std;
class xxx{
public: int a[]; // Why this line is not giving error.
};
int main(int argc, char *argv[])
{
xxx x1;
cout<<sizeof(x1); //Q=Why this code is not giving error.
return 0;
}
As the others have said, an object in C++ can never have size 0.
However, since the code isn’t valid C++ in the first place (arrays cannot be empty) this is inconsequential. The compiler just does what it wants.
GCC with -pedantic rejects this code. MSVC at least warns. My version of clang++ with -pedantic ICEs but does emit a warning before that.
You're not using a standard-compliant compiler. An object size can't be 0, even an empty class or struct has size 1. Moreover, the array dimension has to be specified.
EDIT: It's strange, ideone also prints out 0. In MSVS I get a warning, but at least the size is 1.
5.3.3. Sizeof
[...] When applied to a class, the result is the number of bytes in an object of that class [...] The size of a most derived class shall
be greater than zero. [...] The result of applying sizeof to a base class subobject is the size of the base class type. [...]
EDIT 2:
I tried the following in MSVS:
xxx a[100];
and it fails to compile. Strange how it doesn't pick up the error beforehand.
That element a in your class xxx is called a flexible array member.
Flexible array members are not in the C++ standard. They are a part of C99. However, many compiler vendors provide flexible array members as a C++ extension.
Your code as-is is not legal C code. It uses C++ specific constructs. Your code is easy to change to C. Change the class to struct, get rid of the public, and change the use of C++ I/O to C's printf. With those changes, your converted code is still illegal C99 code. Flexible array members are only allowed as the last element of a structure that is otherwise non-empty.
Apparently your vendor took the flexible array member concept over to C++, but not the constraint that the structure be otherwise non-empty.
The size of an object can not be zero. even if the class is empty, its size is never zero.
Checkout the link to know more Bjarne Stroustrup's C++ Style and Technique FAQ.
Related
This question already has answers here:
Why aren't variable-length arrays part of the C++ standard?
(10 answers)
Closed 4 years ago.
I'm using MinGW to compile for C++11 and I found out that this doesn't throw an error:
int S;
cin>>S;
char array[S];
While this does ("storage size of 'array' isn't known"):
char array[];
To me, the size is also unknown in the first case, as it depends on what the user input is.
As far as I knew, automatic arrays are allocated at compile time in stack memory. So why wouldn't the first example fail?
It's not. C++ doesn't have variable-length arrays, though some compilers allow it as an extension of the language.
You are apparently not aware of the GNU GCC extension Arrays of Variable Length. Therefore your first code compiles.
The error message is something different. You have to specify the array length.
gcc has the -pedantic switch - enabling this switch the compiler will report your first code as invalid:
warning: ISO C++ forbids variable length array ‘array’
Read also this thread What is the purpose of using -pedantic in GCC/G++ compiler?
Use very carefully compiler extensions because should you port your code to another compiler then you are in big trouble.
[This answers the original version of the question which asked about a static array; Deduplicator corrected this misconception, but now the question is missing a part.]
If your assumption that this piece of code defined a static array were correct, you'd be wondering for a good reason indeed: Something that is determined at compile time, like data with static storage duration, can obviously not depend on user input at run time. This truism is independent of any specific language.
The array defined in your code snippet has, by contrast, automatic storage duration, vulgo is created on the stack. A complete minimal working example would have made the case clearer: It would have shown that the code is in a function.
Objects with automatic storage duration can be created as needed at run time; there is no logical problem preventing that, which should fix your general headache ;-).
But note that, as some programmer dude correctly remarked, standard C++ nevertheless does not permit the definition of arrays whose size is not known at compile time; standard C does though, since C99. The rationale for C++ no following that amendment is that C++ provides better means for the use case, like the vector template. gcc, which is the compiler used in MinGW, permits this as an extension (and why not — it's available in the compiler anyway).
I know a class can't have a member of the same class, e.g.
class Sample {
int a = 0;
Sample s; // error, object would need infinite size
};
But how come having a pointer is okay?
class Sample {
// this compiles, but isn't it essentially the same
// as above?
Sample() { s = new Sample(); }
int a = 0;
Sample *s;
};
A pointer as a member is allowed because a pointer has a fixed size (4 bytes in a 32bit app, 8 bytes in a 64bit app), so the compiler can know the full size of Sample at compile time, it is not dependent on what the pointer is pointing at during runtime.
Creating an instance of Sample inside of the Sample constructor is not a syntax error, so the compiler allows it, but it will cause an infinite recursion loop at runtime. So don't do it.
Speaking very generally, the compiler is good at detecting problems with types, and bad at detecting problems with values.
In the latter case, sometimes that's because it can't (how can it know about things that happen ten years later?), and sometimes it's because it can't really be bothered (read: the standard doesn't require it to do mathematically difficult things, because that would be kind of mean).
In the first example, the recursive definition is a problem shown by the types. The compiler always knows that you've done it. In fact, there is physically no way for it to create a program matching that source code: no such thing can mathematically exist — it would go on forever.
But runtime indirection opens up new opportunities! A pointer doesn't have to point to anything. You could have left s uninitialised, or initialised it to nullptr, which would be fine. You could have left the choice up to an if with a rand() call. The best the compiler could do is analyse the constructor body to see whether you recursively instantiate a Sample. Ultimately, though, that's more effort than either the compiler or the standard are willing to put in1, so it becomes your problem.
In short: that's just how it is.
1. What if your constructor body were in another translation unit? This time it's not, but C++ likes general rules…
class Sample {
int a = 0;
Sample s; // error, object would need infinite size
};
The definition of Sample is unfinished at the place where you've declared Sample s;, therefore compiler doesn't know how much size it should be allocating ... it doesn't know what is sizeof(Sample).
Pointer to itself i.e. Sample *s;, is standard size depending upon your target platform for which you compile your code.
There is an old post asking for a construct for which sizeof would return 0. There are some high score answers from high reputation users saying that by the standard no type or variable can have sizeof 0. And I agree 100% with that.
However there is this new answer which presents this solution:
struct ZeroMemory {
int *a[0];
};
I was just about to down-vote and comment on it, but time spent here taught me to check even the things that I am 100% sure on. So... to my surprise both gcc and clang show the same results: sizeof(ZeroMemory) == 0. Even more, sizeof a variable is 0:
ZeroMemory z{};
static_assert(sizeof(z) == 0); // Awkward...
Whaaaat...?
Godbolt link
How is this possible?
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:
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.
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.
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.
As pointed out by Jarod42 zero size arrays are not standard C++, but GCC and Clang extensions.
Adding -pedantic produces this warning:
5 : <source>:5:12: warning: zero size arrays are an extension [-Wzero-length-array]
int *a[0];
^
I always forget that std=c++XX (instead of std=gnu++XX) doesn't disable all extensions.
This still doesn't explain the sizeof behavior. But at least we know it's not standard...
In C++, a zero-size array is illegal.
ISO/IEC 14882:2003 8.3.4/1:
[..] If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero. The constant expression specifies the bound of (number of elements in) the array. If the value of the constant expression is N, the array has N elements numbered 0 to N-1, and the type of the identifier of D is “derived-declarator-type-list array of N T”. [..]
g++ requires the -pedantic flag to give a warning on a zero-sized array.
Zero length arrays are an extension by GCC and Clang. Applying sizeof to zero-length arrays evaluates to zero.
A C++ class (empty) can't have size 0, but note that the class ZeroMemory is not empty. It has a named member with size 0 and applying sizeof will return zero.
I am doing the following for initializing an array in c++
int a;
cin>>a;
float b[a];
This works and compiles in my computer. IS this correct? I thought that we can only do this if a was a const int.
Depends on you definition of "correct".
This is called variable-length array (or just VLA) and it's not officially supported in the current versions of C++ (100% sure for C++03 and before, 99.99% sure for C++11), but it is in C.
Some compilers allow this as a compiler extension.
It's not about whether a is a constant int. It's about whether a has a initial value assigned at comipling time. Compiler needs to allocate storage according to a const int value. C++ standard doesn't support variable length array right now.
In C99, this syntax of variable length array is valid, but C++ standard says no. It is a very useful feature, leaving all the hairy memory allocating stuff to the compiler.
In GCC and Clang, this feature is supported as a compiler extension, so you won't get any warning and error. But MSVC compiler will put an error message that says cannot allocate an array of constant size 0, So it is compiler specific.
The compiler that supports this feature may have convert your code with new operator.
int a;
cin>>a;
float *b = new float[a];
This is valid in C++ standard.
Another thing is that though it is called variable-length array, it is not length-variable at all. Once it is defined, its length is a constant value which never change. You can't expand it or shrink it.
It is much better to use the vector container which is truly length variable, and with much more scalability and adaptivity.
See the post for more discussion on Why aren't variable-length arrays part of the C++ standard?
All,
This has been bugging me for a while now. In C\C++( i guess java and .NET as well) we do not have to specify the row index in a multi-dimensional array.
So, for example i can declare an array of ints as such:
int Array[][100];
I think static arrays in general are represented as contiguous memory on the stack. So, taking a column-major representation, how does the compiler know how much memory to allocate in the above case as it's missing one of the dimensions?
In C++ language you can't just do
int Array[][100]; /* ERROR: incomplete type */
because that would be a definition of an object of incomplete type, which is explicitly illegal in C++. You can use that in a non-defining declaration
extern int Array[][100];
(or as a static member of a class), but when it will come to the actual definition of the same array object both sizes will have to be specified explicitly (or derived from an explicit initializer).
In C the situation is not much different, except that in C there are such things as tentative definitions which let you write
int Array[][100];
However, a tentative definition in this regard is pretty similar to a non-defining declaration, which is why it is allowed. Eventually you will have to define the same object with explicitly specified size in the same translation unit (some compilers don't require that as an non-stanard extension). If you try something like that in a non-tentative definition, you'll get an error
static int Array[][100]; /* ERROR: incomplete type */
So, if you think of it, aside from tentative definitions, the situation in C and C++ is not much different: it is illegal to define objects of incomplete type in these languages and an array of unspecified size is an incomplete type.
In java and .NET, don't think about "the stack" -- objects live on the heap. And in C, that's just a declaration -- only a definition actually reserves memory! So that would NOT be an acceptable definition -- if you put it as the only line in file a.c:
$ gcc -c a.c
a.c:1: warning: array ‘Array’ assumed to have one element
so gcc is just treating it as if it were int Array[1][100];, as it warns you it's doing.
It does not know how much memory to allocate, what he knows with array[] is that array is a pointer (like int *array). array[][100] ( someone please correct me if i am wrong ) is the same as array[100].