Confused results of the operator 'sizeof'

I recently tried this code and got a little confused. See the following ads:

static st; auto au; register reg; volatile vl; const cn; 

All of them allocate memory 4 bytes (on 32-bit GCC). But when I try to print (using the printf function) their sizes, they do not work and do not give errors.

  sizeof(const) // worked and printed 4 sizeof(volatile) // worked and printed 4 sizeof(auto) // error: expected expression before 'auto' sizeof(static) // error: expected expression before 'static' sizeof(register) // error: expected expression before 'register' 

I doubt that the keywords auto, static, register also allocate memory of 4 bytes (on a 32-bit architecture).

But why do they give errors unlike const and volatile ?

+7
c gcc sizeof declaration
source share
5 answers

In C prior to the 1999 standard, an undefined type by default will be int in many contexts.

C99 has dropped this rule, and omitting this type is now illegal (strictly speaking, this is a violation of the constraint that requires diagnostics - which could be a fatal warning). In any case, omitting the int type has always been a bad idea. (It goes back to the C-precursors of the BCPL and B languages, which is pretty much impersonal.)

 static st; auto au; register reg; volatile vl; const cn; 

These declarations are legal in C90 (and all variables are of type int ), but they are not valid in C99.

 sizeof(const) sizeof(volatile) 

Most likely, this is indeed legal in the C90 (but not in the C99). const or volatile itself is a type name equivalent to const int and volatile int , respectively. Syntactically const and volatile are type classifiers.

 sizeof(auto) sizeof(static) sizeof(register) 

The difference is that it is:

 const int x = 42; 

defines x as an object of type const int , and this:

 static int x = 42; 

defines x as a static object of type int ( static not part of the type).

These are all syntax errors because auto , static and register are not type names. These keywords are storage class specifiers.

This explains why the first two sizeof expressions seem to work, while the others do not. But this is not particularly useful to know, because if you specify the type int (which you should always), it does not matter that sizeof(const) is valid (in C90, not C99).

The bottom line is that you should always specify a type in any declaration. And although you can legally write sizeof (const int) , it guarantees that it will be the same as sizeof (int) , so there is not much point in using const in this context.

+17
source share

Before C99, if you did not specify a type, then int is implied, which is what happens in your code. It seems that in practice, even in C99 mode, gcc and clang will only give warnings. This is the case when compiler warnings are your friend, I tried this in clang -Wall :

 printf( "%zu\n", sizeof(const) ) ; 

and he warns me:

 warning: type specifier missing, defaults to 'int' [-Wimplicit-int] 

All announcements here:

 static st; auto au; register reg; volatile vl; const cn; 

also have an implied int type.

We see that C99 removed the implicit int assumption:

A declaration that lacks a type specifier no longer implies an implied int value. The C standards committee decided that it was more important for compilers to diagnose an unintentional omission of a type specifier than to silently process legacy code based on an implicit int. In practice, compilers can display a warning, then assume int and continue translating the program.

If we look at the draft standard C99 In the fifth section of paragraph 5, the following is stated:

[...] Major changes that occurred in the previous edition include:

and has the following brand:

- remove implicit int

Refresh

So why does sizeof not look like storage class specifiers like static and auto, but in the way with type classifiers like const and volatile, the behavior seems incompatible with how declarations work, and if the implicit int assumption still works?

Well, if we look at the grammar for sizeof in the draft standard section 6.5.3 , this would be the following:

 sizeof unary-expression sizeof ( type-name ) 

Thus, neither the type specifier nor the storage class specifiers are an expression, and the type specifier is the type name, if we look at section 6.7.6 , the grammar for the type name is as follows:

 type-name: specifier-qualifier-list abstract-declaratoropt 

and 6.7.2.1 gives us a grammar for a list of qualifiers, which looks like this:

 specifier-qualifier-list: type-specifier specifier-qualifier-listopt type-qualifier specifier-qualifier-listopt <- Bingo allows type qualifier 

So we can see that sizeof simply does not accept storage class specifiers, even if the type is explicitly specified for int, so even the following message is an error:

 printf( "%zu\n", sizeof(static int) ) ; 

and clang tells us:

 error: expected expression printf( "%zu\n", sizeof(static int) ) ; ^ 

and we can also see that type names will not work with sizeof without () :

 printf( "%zu\n", sizeof int ) ; 

creates an error:

 error: expected expression 

but unary expressions work with () , as I explained earlier here .

+10
source share

The auto , static , register keys do not identify any type, but change the way that a variable of this type is stored or accessed.

So:

 sizeof(auto) // error: expected expression before 'auto' sizeof(static) // error: expected expression before 'static' sizeof(register) // error: expected expression before 'register' 

does not make sense because you are not requesting a size of any type. Instead of this:

 sizeof(const) // worked and printed 4 sizeof(volatile) // worked and printed 4 

These types identify: volatile int and const int . Therefore, you can use sizeof for them.

Note that when you declare your variables, the compiler assumes int as its main type. Most compilers (GCC, Clang) will give warnings if you rely on this behavior.

+1
source share

extern , static , auto , register are called the qualifier of the storage class , and const , restrict , volatile are called the classifier type .

For type specifiers, when used without a type specifier, int implicitly specified in C89.

C89 Β§3.5.2 Type specifiers

int , signed , signed int or type specifiers

These listed types are the same with each other. Although type specifiers were not deleted on C99 in the same section:

C99 Β§6.7.2 Type Specifiers

int , signed or signed int

+1
source share

Your ads are not valid, so the results are largely irrelevant.

The size of a variable / object depends on its data type, for example int or float . The keywords that you tried to change are how the compiler processes the variable / object, but they do not change or dictate its type (therefore they have nothing to do with its size).

For your declarations, const and volatile compiler most likely did not specify an int type by default (but this is not the behavior you should ever rely on).

0
source share

All Articles