为什么变量不能在C中的2个文件中定义两次

时间:2021-06-16 08:45:04

Why can't I have int a; in 2 C files. I intend to combine both to make executable. I know from experience that I can't, but I want to find where the standard C99 says this and seal my understanding.

为什么我不能拥有一个;在2个C文件中。我打算将两者结合起来制作可执行文件。我从经验中知道我不能,但我想找到标准C99所说的位置并密封我的理解。

I am reading ISO C99 standard from http://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf. It says on page 42:

我正在阅读http://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf中的ISO C99标准。它在第42页说:

6.2.2 Linkages of identifiers

6.2.2识别者的联系

1 An identifier declared in different scopes or in the same scope more than once can be made to refer to the same object or function by a process called linkage.There are three kinds of linkage: external, internal, and none.

1可以通过一个称为连接的过程,在不同的范围或相同的范围内多次声明一个标识符。通过一个名为linkage的过程来引用同一个对象或函数。有三种连接:外部,内部和无。

2 In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function. Within one translation unit, each declaration of an identifier with internal linkage denotes the same object or function. Each declaration of an identifier with no linkage denotes a unique entity.

2在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或功能。在一个翻译单元内,具有内部链接的标识符的每个声明表示相同的对象或功能。没有链接的标识符的每个声明表示一个唯一的实体。

3 If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static,the identifier has internal linkage.

3如果对象或函数的文件范围标识声明包含存储类指定静态,则标识符具有内部链接。

4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

4对于在存储类规范外部声明的标识符,在该范围内可以看到该标识符的先前声明,如果先前声明指定内部或外部链接,则后面声明中标识符的链接与在先前声明中指定的联系。如果没有先前的声明可见,或者如果先前的声明没有指定链接,则标识符具有外部链接。

5 If the declaration of an identifier for a function has no storage-class specifier,its linkage is determined exactly as if it were declared with the storage-class specifier extern.If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

5如果函数的标识符声明没有存储类指定符,则其链接的确定就像是使用存储类指定符extern声明的。如果对象的标识符声明具有文件范围且没有存储空间 - 特定的,它的联系是外在的。

After reading this it looks that if I declare a variable like say int a; in 2 source files. then both have external linkage as per rule 5 and 4. and then as per rule 2, both should refer to the same object. Then why does the compiler create problem. Where in the standard it is hinted that we can't declare like this in 2 source files and this should throw compilation error. Firstly, where in the standard, it says that int a is a definition, and then where it says that 2 instances of definitions are not acceptable. I know that it is not allowed from my experience, but it would be very useful to me, if I can find this in the standard and seal my understanding.

看完之后看起来如果我声明一个变量就像说int a;在2个源文件中。然后根据规则5和4都有外部链接,然后根据规则2,两者都应该引用同一个对象。那为什么编译器会产生问题。在标准中,暗示我们不能在2个源文件中声明这样,这应该抛出编译错误。首先,在标准中,它表示int a是一个定义,然后它表示2个定义实例是不可接受的。我知道这是不允许的,但是如果我能在标准中找到并密封我的理解,这对我来说非常有用。

Do the following excerpts from the standard in combination amount to this rule? or I have missed that glue? :

请将以下标准的摘录与此规则相结合?或者我错过了胶水? :

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名称,是标识符的(唯一)声明。

As discussed in 5.1.1.1, the unit of program text after preprocessing is a translation unit, which consists of a sequence of external declarations. These are described as ‘‘external’’ because theyappear outside anyfunction (and hence have file scope). As discussed in 6.7, a declaration that also causes storage to be reserved for an object or a function named by the identifier is a definition.

正如5.1.1.1中所讨论的,预处理后的程序文本单元是一个翻译单元,它由一系列外部声明组成。这些被描述为“外部”,因为它们出现在任何功能之外(因此具有文件范围)。正如6.7中所讨论的那样,一个声明也会导致为对象或由标识符命名的函数保留存储,这是一个定义。

An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

外部定义是外部声明,它也是函数(除了内联定义)或对象的定义。如果在表达式中使用了使用外部链接声明的标识符(除了作为sizeof运算符的操作数的一部分,其结果是整数常量),整个程序中的某个地方应该只有一个外部定义用于标识符;否则,不得超过一个。

Thanks.

谢谢。

1 个解决方案

#1


16  

I think you need 6.9.2/2:

我认为你需要6.9.2 / 2:

A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

具有文件范围而没有初始化程序且没有存储类说明符或存储类说明符为静态的对象的标识符声明构成暂定定义。如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,那么行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元的结尾,初始化程序等于0。

and 6.9/5:

和6.9 / 5:

An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

外部定义是外部声明,它也是函数(内联定义除外)或对象的定义。如果在表达式中使用通过外部链接声明的标识符(而不是作为sizeof运算符的操作数的一部分,其结果是整数常量),则整个程序中的某个地方应该只有一个标识符的外部定义;否则,不得超过一个。

Basically, int a; is a tentative definition. You can have multiple tentative definitions in a single translation unit but the effect is the same as having one non-tentative external definition (e.g. something like int a = 0;). Having more that one definition of an object with external linkage in a program is a violation of 6.9/5.

基本上,int a;是一个暂定的定义。您可以在单个翻译单元中具有多个暂定定义,但效果与具有一个非暂定外部定义(例如,类似于int a = 0;)的效果相同。在程序中具有多个具有外部链接的对象的定义违反了6.9 / 5。

Note that it is a "common extension" to allow more than one external definitions of an object so long as at most only one is initialized and the definitions agree (see J.5.11).

请注意,只要最多只有一个被初始化并且定义一致,它是允许对象的多个外部定义的“公共扩展”(参见J.5.11)。

#1


16  

I think you need 6.9.2/2:

我认为你需要6.9.2 / 2:

A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.

具有文件范围而没有初始化程序且没有存储类说明符或存储类说明符为静态的对象的标识符声明构成暂定定义。如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,那么行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元的结尾,初始化程序等于0。

and 6.9/5:

和6.9 / 5:

An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

外部定义是外部声明,它也是函数(内联定义除外)或对象的定义。如果在表达式中使用通过外部链接声明的标识符(而不是作为sizeof运算符的操作数的一部分,其结果是整数常量),则整个程序中的某个地方应该只有一个标识符的外部定义;否则,不得超过一个。

Basically, int a; is a tentative definition. You can have multiple tentative definitions in a single translation unit but the effect is the same as having one non-tentative external definition (e.g. something like int a = 0;). Having more that one definition of an object with external linkage in a program is a violation of 6.9/5.

基本上,int a;是一个暂定的定义。您可以在单个翻译单元中具有多个暂定定义,但效果与具有一个非暂定外部定义(例如,类似于int a = 0;)的效果相同。在程序中具有多个具有外部链接的对象的定义违反了6.9 / 5。

Note that it is a "common extension" to allow more than one external definitions of an object so long as at most only one is initialized and the definitions agree (see J.5.11).

请注意,只要最多只有一个被初始化并且定义一致,它是允许对象的多个外部定义的“公共扩展”(参见J.5.11)。