为什么我不能在2个C文件中使用 int a; 。我打算将两者结合起来制作可执行文件。 我从经验中知道我不能,但我想找到标准C99所说的内容并密封我的理解。
我正在阅读http://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf的ISO C99标准。它在第42页说:
6.2.2识别者的联系
1一个标识符以不同的方式声明 范围或在同一范围内 一旦可以提到相同的 被称为进程的对象或函数 联系。有三种 连接:外部,内部和无。
2在翻译单元和 构成整体的图书馆 程序,每个声明 特别是与外部的认同 连接表示相同的对象或 功能。在一个翻译单元内, 每个声明的声明 内部联系表示相同 对象或功能。每个声明 一个没有联系的识别者 表示一个独特的实体。
3如果声明范围的声明 识别对象或功能 包含存储类规范 静态的,识别者有内在的 键。
4对于用声明的声明 存储类指定外部的 事先声明的范围 如果是先前的那个标识符是可见的 声明内部或 外部联系,联系 在后来的声明中确定的是 与指定的链接相同 事先声明。如果没有事先 声明是可见的,或者如果是 事先声明没有联系, 然后识别者有外在的 键。
5如果声明了身份证明 对于一个函数没有存储类 具体而言,它的联系是确定的 就像它被声明一样 存储级别的特定外部。如果 声明的声明 对象有文件范围,没有 存储级特定,它的联系是 外部
阅读本文之后,看起来我在两个源文件中声明了一个像 int a; 这样的变量。然后根据规则5和4都有外部链接,然后根据规则2,两者都应该引用同一个对象。那为什么编译器会产生问题。在标准中,暗示我们不能在2个源文件中声明这样,这应该抛出编译错误。首先,在标准中,它表示int a是一个定义,然后它表示2个定义实例是不可接受的。我知道我的经验是不允许的,但如果我能在标准中找到并密封我的理解,那对我来说非常有用。
根据此规则,以下标准的摘录是否合并?或者我错过了那个胶水?:
宣言具体说明 一组的解释和属性 识别者。一个定义 标识符是对此的声明 确定: - 对象,原因 为此保留的存储空间 宾语; - 一个功能,包括 功能体; - 列举 常量或typedef名称,是 (仅)声明的声明。
如5.1.1.1中所述,单位为 预处理后的程序文本是 翻译单元,由一个 外部声明的顺序。 这些被描述为''外部'' 因为它们出现在任何功能之外 (因此有文件范围)。如 在6.7中讨论,声明 还会导致保留存储空间 由...命名的对象或函数 识别是一种定义。
外部定义是一种外部声明,也是一种定义 一个函数(除了内联 定义)或对象。如果 识别与外部一致 链接用于表达式 (除了作为操作数的一部分 一个sizeof运算符,其结果是 整数常数),在某处 整个程序应该是准确的 一个外部的定义 identi科幻儿;否则,应该有 不超过一个。
感谢。
答案 0 :(得分:17)
我认为你需要6.9.2 / 2:
具有没有初始化程序的文件范围且没有存储类说明符或存储类说明符
static
的对象的标识符声明构成暂定定义 。如果翻译单元包含一个或多个标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,那么行为就像翻译单元包含该标识符的文件范围声明一样,复合类型为翻译单元结尾,初始化程序等于0。
和6.9 / 5:
外部定义是外部声明,也是函数的定义 (内联定义除外)或对象。如果用外部声明的标识符 linkage用在表达式中(除了作为
sizeof
运算符的操作数的一部分之外) 其结果是一个整数常量),在整个程序的某个地方应该有 正好是标识符的一个外部定义;否则,不得超过一个。
基本上,int a;
是暂定定义。您可以在单个翻译单元中具有多个暂定定义,但效果与具有一个非暂定外部定义(例如int a = 0;
之类的内容)相同。在程序中有一个具有外部链接的对象的更多定义违反了6.9 / 5.
请注意,只要一个对象的外部定义最多只有一个被初始化并且定义一致,它是一个“公共扩展”(参见J.5.11)。