I recently tried this code and was a little confused. See the following declarations:
static st;
auto au;
register reg;
volatile vl;
const cn;
They all are allocating memory of 4 bytes (on 32 bit GCC). But when i try to print (using printf
function) their sizes, they are not working and giving 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’
My doubt is auto, static, register
keywords also allocating memory of 4 bytes(on 32 bit arch).
But why these are giving errors unlike const
and volatile
?
In C prior to the 1999 standard, an unspecified type would default to int
in many contexts.
C99 dropped that rule, and omitting the type is now illegal (strictly speaking, it's a constraint violation, requiring a diagnostic -- which could be a non-fatal warning). In any case, omitting the int
type has always been a bad idea. (It goes back to C's predecessor languages BCPL and B, which where largely typeless.)
static st;
auto au;
register reg;
volatile vl;
const cn;
These declarations are all legal in C90 (and all the variables are of type int
), but they're invalid in C99.
sizeof(const)
sizeof(volatile)
Somewhat to my surprise, these are actually legal in C90 (but not in C99). const
or volatile
by itself is a type name, equivalent to const int
and volatile int
, respectively. Syntactically, const
and volatile
are type qualifiers.
sizeof(auto)
sizeof(static)
sizeof(register)
The distinction is that this:
const int x = 42;
defines x
to be an object of type const int
, while this:
static int x = 42;
defines x
to be a static object of type int
(static
isn't part of the type).
These are all syntax errors, because auto
, static
, and register
are not type names. Those keywords are storage-class specifiers.
This explains why the first two sizeof
expressions seem to work, and the others do not. But that's not particularly useful to know, because if you specify the type int
(which you always should), it doesn't matter that sizeof(const)
happens to be valid (in C90, not in C99).
The bottom line is that you should always specify the type in any declaration. And though you can legally write sizeof (const int)
, it's guaranteed to be the same as sizeof (int)
, so there's not much point in using const
in that context.
Prior to C99 if you did not specify a type then int would be implied which is what is happening in your code. It looks like in practice even in C99 mode gcc
and clang
will just produce warnings. This is a case where compiler warnings are your friend, I tried this in clang -Wall
:
printf( "%zu\n", sizeof(const) ) ;
and it warns me:
warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
All the declarations here:
static st;
auto au;
register reg;
volatile vl;
const cn;
also have an implied int type.
We can see that C99 removed the implicit int assumption:
a declaration that lacks a type specifier no longer has int implicitly assumed. The C standards committee decided that it was of more value for compilers to diagnose inadvertent omission of the type specifier than to silently process legacy code that relied on implicit int. In practice, compilers are likely to display a warning, then assume int and continue translating the program.
If we look at the draft C99 standard Forward section paragraph 5 includes the following:
[...]Major changes from the previous edition include:
and has the following bullet:
— remove implicit int
Update
So why does sizeof
not like storage class specifiers like static and auto but is okay with type qualifiers like const and volatile, the behavior seems inconsistent with how the declarations work and should the implicit int assumption still work?
Well if we look at the grammar for sizeof
in the draft standard section 6.5.3
it is as follows:
sizeof unary-expression
sizeof ( type-name )
So neither a type qualifier nor a storage class specifiers is an expression but a type qualifier is a type-name, if we look at section 6.7.6
the grammar for type-name is as follows:
type-name:
specifier-qualifier-list abstract-declaratoropt
and 6.7.2.1
gives us the grammar for specifier-qualifier-list which is as follows:
specifier-qualifier-list:
type-specifier specifier-qualifier-listopt
type-qualifier specifier-qualifier-listopt <- Bingo allows type qualifier
So we can see that sizeof
just does not accept storage class specifiers even if the type is explicitly specified to int, so even the following 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 further see that type names won't work with sizeof
without ()
:
printf( "%zu\n", sizeof int ) ;
produces an error:
error: expected expression
but unary expressions work with ()
as I explained previously here.
The auto
, static
, register
keywords don't identify any type, but modify the way a variable of that 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’
make no sense, because you're not requesting the size of any type. Instead:
sizeof(const) // worked and printed 4
sizeof(volatile) // worked and printed 4
These identify types: volatile int
and const int
. So you can use sizeof
on them.
Notice that when you're declaring your variables, the compiler is assuming int
as their underlying type. Most compilers (GCC, Clang) will emit warnings if you're relying on this behaviour.
extern
, static
, auto
, register
are called storage-class-specifier, while const
, restrict
, volatile
are called type-qualifier.
For type-qualifiers, when used without type-specifier, int
is implicitly specified in C89.
C89 §3.5.2 Type specifiers
int
,signed
,signed int
, or no type specifiers
These types listed are the same with each other. While no type specifiers has been removed in C99 in the same section:
C99 §6.7.2 Type specifiers
int
,signed
, orsigned int
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With