简体   繁体   English

为什么允许多次声明typedef标识符?

[英]Why are typedef identifiers allowed to be declared multiple times?

From the C99 standard, 6.7(5): 从C99标准来看,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. 对于枚举常量或typedef名称,是标识符的(唯一)声明。

If identifiers with typedef are in fact definitions, then why are they allowed to be declared more than once? 如果带有typedef标识符实际上是定义,那么为什么允许它们被多次声明? 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. 我期待该程序给我一个多重定义错误。

C99 is different from C11 C99与C11不同

The rules change between C99 and C11 (and the C11 rules match the C++ rules, as I understand it). 规则在C99和C11之间变化(并且C11规则与C ++规则匹配,据我所知)。 Note that in both standards, ¶3 is in the Constraints section and ¶5 is in the Semantics section. 请注意,在这两个标准中,¶3在Constraints部分中,¶5在Semantics部分中。 That is important for error messages — constraint violations require a diagnostic. 这对于错误消息很重要 - 约束违规需要诊断。

ISO/IEC 9899:1999 §6.7 Declarations ISO / IEC 9899:1999§6.7声明

¶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. ¶3如果标识符没有链接,则除了6.7.2.3中规定的标记之外,标识符(在声明符或类型说明符中)的声明不应超过一个具有相同作用域和相同名称空间的声明。

5 A declaration specifies the interpretation and attributes of a set of identifiers. 5声明指定一组标识符的解释和属性。 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) 对于一个函数,包括函数体; 98)
  • for an enumeration constant or typedef name, is the (only) declaration of the identifier. 对于枚举常量或typedef名称,是标识符的(唯一)声明。

ISO/IEC 9899:2011 §6.7 Declarations ISO / IEC 9899:2011§6.7声明

¶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: ¶3如果标识符没有链接,则标识符的声明(在声明符或类型说明符中)不得超过一个具有相同作用域和相同名称空间的声明,但以下情况除外:

  • a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type; 如果类型不是可变修改类型,则可以重新定义typedef名称以表示与其当前相同的类型;
  • tags may be redeclared as specified in 6.7.2.3. 标签可以按照6.7.2.3中的规定重新声明。

¶5 A declaration specifies the interpretation and attributes of a set of identifiers. ¶5声明指定一组标识符的解释和属性。 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) 对于一个函数,包括函数体; 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. 对于typedef名称,是标识符的第一个(或唯一的)声明。

Lundin noted that the Standard C Committee's web site contains n1360 , a one page document detailing why this change was made. Lundin 指出 ,标准C委员会的网站包含n1360 ,这是一份单页文件,详细说明了为何进行此项更改。 Basically: C++ does it; 基本上:C ++就是这样做的; 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. 如果您的代码正在编译,那么它将根据C11规则或C ++规则进行编译。 It is not being compiled under (strict) C99 rules. 它不是根据(严格)C99规则编译的。

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. 请注意,除非您另有说明,否则GCC的最新版本允许重新定义,但也请注意John Bollinger报告 ,即GCC 4.4.7(在未识别的平台上)不允许在C99模式下重新定义。

Consider the file retypedef.c : 考虑文件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 4.9.1在Mac OS X 10.9.5上进行编译,得到:

$ 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). 除非使用-pedantic ,否则它不会抱怨,只有在请求C99时才符合要求(在C11中重新定义同一范围内的typedef是标准的)。

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. 如果我使用gcc 4.4.7编译你的代码,那么它实际上确实报告了关于x的重新定义的错误。

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. typedef类似于原型化函数或结构 - 它们声明具有一些编译时间含义的标识符,但没有运行时含义。 For example, the following wouldn't compile: 例如,以下内容无法编译:

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

because x does not name a variable; 因为x没有命名变量; it is only a compile time alias for the name int . 它只是名称int的编译时别名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM