7

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?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
gangadhars
  • 2,584
  • 7
  • 41
  • 68
  • Size of keyword? Why do you even expect a result back? – SwiftMango Oct 31 '13 at 15:02
  • The type is defaulted to int. It's the same thing that happens when you declare `unsigned a;` – StoryTeller - Unslander Monica Oct 31 '13 at 15:02
  • Title says "C", and tags are C and C++. Does C have `auto`? *Pick a language* instead of shotgunning. – crashmstr Oct 31 '13 at 15:04
  • @texasbruce i'm expecting result as 4 bytes. For example, register keyword stores in CPU registers. It can directly give `cpu register size` as the result – gangadhars Oct 31 '13 at 15:04
  • 4
    Yes, C has `auto`. It means `auto`matic storage. – peppe Oct 31 '13 at 15:04
  • 1
    from classical C (or even B) comes the infamous "everything not type declared is an int" feature that you are seeing here, so all your stuff are ints. – PlasmaHH Oct 31 '13 at 15:07
  • You are probably aware, but it is worth pointing out that you can of course still do `sizeof au`, `sizeof st` and `sizeof reg`, and get the same value as `sizeof int` in each case. – Magnus Hoff Oct 31 '13 at 15:09
  • @MagnusHoff: yes i know. but why they are not working when we directly giving? – gangadhars Oct 31 '13 at 15:11
  • @PlasmaHH: That rule does not exist in C++. See footnote [92] in the C++11 Standard: "There is no special provision for a decl-specifier-seq that lacks a type-specifier or that has a type-specifier that only specifies cv-qualifiers. The “implicit int” rule of C is no longer supported." – John Dibling Oct 31 '13 at 15:24
  • Simply compile with a C standard compiler and the code will not compile (C99 or C11). – Lundin Oct 31 '13 at 15:27
  • @Lundin How to know which c compiler I'm using? – gangadhars Oct 31 '13 at 15:34
  • @SGG You claim to be using GCC so I would assume that's the one? Simply compile with correct compiler settings for standard C: `gcc -std=c99 -pedantic-errors -Wall`. Or if you have an brand new version of GCC, I suppose it has -std=c11. – Lundin Oct 31 '13 at 16:07
  • @JohnDibling: The OP is about C code compiled with a C compiler, clearly being about C, and not at all about C++ – PlasmaHH Oct 31 '13 at 16:43
  • @PlasmaHH: Is `auto` part of C now? – John Dibling Oct 31 '13 at 16:43
  • @Lundin it seems in practice that even though *C99* removed implicit int, many compilers will allow it with a warning. Sadly it seems even with `-pedantic-errors`. – Shafik Yaghmour Oct 31 '13 at 17:29
  • @ShafikYaghmour Not a single line of the OP's code passes `gcc -std=c99 -pedantic-errors -Wall`. I don't know how you managed to compile it without errors. – Lundin Nov 01 '13 at 07:30
  • @Lundin I just tried again and `clang` does indeed still allow it with only warning although `gcc` does not, I thought both did yesterday [see clang working here](http://coliru.stacked-crooked.com/a/60e2adcd62b61373). – Shafik Yaghmour Nov 01 '13 at 09:34
  • @ShafikYaghmour Then it would seem that Clang doesn't follow the standard. If that is the case, I would uninstall it and replace with GCC. – Lundin Nov 01 '13 at 10:06
  • @JohnDibling: C always had an `auto` keyword, yes. – PlasmaHH Nov 01 '13 at 10:20
  • @Lundin that is a bit extreme, although it does look like a bug, let me see what it takes to report it. – Shafik Yaghmour Nov 01 '13 at 13:03

5 Answers5

17

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.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
10

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.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
1

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.

peppe
  • 21,934
  • 4
  • 55
  • 70
1

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, or signed int

Community
  • 1
  • 1
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
0

Your declarations are all invalid, so the results are largely irrelevant.

The size of a variable/object depends on its data type, such as int or float. The keywords you tried modify the way the compiler handles the variable/object, but they do not alter or dictate its type (therefore they have no bearing on its size).

For your const and volatile declarations, the compiler was likely defaulting to type int (but that's not behaviour you should ever rely on).

Peter Bloomfield
  • 5,578
  • 26
  • 37