Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are typedef identifiers allowed to be declared multiple times?

Tags:

c

typedef

c99

c11

From the C99 standard, 6.7(5):

A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that: for an object, causes storage to be reserved for that object; for a function, includes the function body; for an enumeration constant or typedef name, is the (only) declaration of the identifier.

If identifiers with typedef are in fact definitions, then why are they allowed to be declared more than once? Example:

int main()
{
  typedef int x;
  typedef int x;
}

Above program compiles with no errors. How is this possible? I was expecting the program to give me a multiple definition error.

like image 668
Abinesh S Prabhakaran Avatar asked Oct 07 '14 16:10

Abinesh S Prabhakaran


3 Answers

C99 is different from C11

The rules change between C99 and C11 (and the C11 rules match the C++ rules, as I understand it). Note that in both standards, ¶3 is in the Constraints section and ¶5 is in the Semantics section. That is important for error messages — constraint violations require a diagnostic.

ISO/IEC 9899:1999 §6.7 Declarations

¶3 If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except for tags as specified in 6.7.2.3.

5 A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that:

  • for an object, causes storage to be reserved for that object;
  • for a function, includes the function body;98)
  • for an enumeration constant or typedef name, is the (only) declaration of the identifier.

 

ISO/IEC 9899:2011 §6.7 Declarations

¶3 If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that:

  • a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
  • tags may be redeclared as specified in 6.7.2.3.

¶5 A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that:

  • for an object, causes storage to be reserved for that object;
  • for a function, includes the function body;119)
  • for an enumeration constant, is the (only) declaration of the identifier;
  • for a typedef name, is the first (or only) declaration of the identifier.

Lundin noted that the Standard C Committee's web site contains n1360, a one page document detailing why this change was made. Basically: C++ does it; some compilers already do it; it is neither hard to do nor subverting anything to permit (require) it.

GCC doesn't always enforce the standard

If your code is compiling, then it is being compiled under the C11 rules, or C++ rules. It is not being compiled under (strict) C99 rules.

Note that sufficiently recent versions of GCC allow the redefinition unless you insist otherwise, but also note the report by John Bollinger that GCC 4.4.7 (on an unidentified platform) does not allow the redefinition at all in C99 mode.

Consider the file retypedef.c:

int main(void)
{
    typedef int x;
    typedef int x;
    x y = 0;
    return y;
}

Compiling on Mac OS X 10.9.5 with GCC 4.9.1, I get:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror           -c retypedef.c
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -pedantic -c retypedef.c
$ gcc -O3 -g -std=c99 -Wall -Wextra -Werror           -c retypedef.c
$ gcc -O3 -g -std=c99 -Wall -Wextra -Werror -pedantic -c retypedef.c
retypedef.c: In function ‘main’:
retypedef.c:4:17: error: redefinition of typedef ‘x’ [-Werror=pedantic]
     typedef int x;
                 ^
retypedef.c:3:17: note: previous declaration of ‘x’ was here
     typedef int x;
                 ^
cc1: all warnings being treated as errors
$

It doesn't complain unless -pedantic is used, and then only if C99 is requested (it is standard compliant to redefine a typedef in the same scope in C11).

like image 83
Jonathan Leffler Avatar answered Oct 10 '22 06:10

Jonathan Leffler


Your program compiles without error because your compiler is being lax (or compiling for a different standard). If I compile your code with gcc 4.4.7 then it in fact does report an error about the redefinition of x.

like image 2
John Bollinger Avatar answered Oct 10 '22 05:10

John Bollinger


For the same reason that other declarations are allowed to be declared multiple times. For example:

void foo(int a);

void foo(int a);

int main()
{
    foo(42);
}

void foo(int a)
{
    printf("%d\n", a);
}

This allows more than one header to declare a function or structure, and allow two or more such headers to be included in the same translation unit.

typedefs are similar to prototyping a function or structure -- they declare identifiers that have some compile time meaning, but no runtime meaning. For example, the following wouldn't compile:

int main()
{
    typedef int x;
    typedef int x;
    x = 42;
}

because x does not name a variable; it is only a compile time alias for the name int.

like image 1
Billy ONeal Avatar answered Oct 10 '22 07:10

Billy ONeal