14

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396

3 Answers3

17

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).

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you.Your answer covered all the details I required. – Abinesh S Prabhakaran Oct 07 '14 at 18:10
  • Any idea why this was changed in C11? Just harmonization with C++ or something else? – Lundin Oct 21 '15 at 14:51
  • @Lundin: I have no specific insight into why. I would assume it was a combination of 'harmonization with C++' and 'it makes sense and is not hard to support'. If you wanted to go through the [C standardization committee](http://www.open-std.org/jtc1/sc22/wg14/) notes, I'm sure you could find the reason why — probably looking at minutes and then finding the document, unless there's a working search option. – Jonathan Leffler Oct 21 '15 at 14:57
  • @JonathanLeffler [This](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1360.htm) is the closest thing to a rationale I have found. If you wish, feel free to add that link to your answer for completeness :) – Lundin Oct 21 '15 at 15:05
  • @Lundin: thanks. See update. I doubt if it was controversial given that it was a one-page document with prior art and C++ compatibility to support the change (and no danger of breaking existing working code). – Jonathan Leffler Oct 21 '15 at 15:13
2

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

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.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • 4
    In fact the quoted section of the standard does say that a typedef declaration is also a definition, and there can only be one _definition_ of any identifier. gcc reports an error for the OP's code, at least with -Wall -pedantic -std=c99. – John Bollinger Oct 07 '14 at 16:12
  • 1
    @John: Ah, I guess I spend too much time in C++ land. I'm still leaving the answer though because as Jonathan Leffler indicates, it is correct in C11. – Billy ONeal Oct 07 '14 at 16:18