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

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

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

6.2.2识别者的联系

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

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

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

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

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

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

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

声明规定了一组标识符的解释和属性。 标识符的定义是对该标识符的声明: – 对于一个对象,导致为该对象保留存储; – 用于function,包括function体; – 对于枚举常量或typedef名称,是标识符的(唯一)声明。

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

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

谢谢。

我认为你需要6.9.2 / 2:

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

和6.9 / 5:

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

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

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