假设我有两个源文件:main.c
和a.c
:
main.c
#include <stdio.h>
int a;
int i;
int i;
int main(void)
{
printf("a = %d\n", a);
printf("i = %d\n", i);
return 0;
}
a.c
int a;
然后,根据最新的C99草案6.9.2
外部对象定义 p。 2(强调我的):
具有文件范围的对象的标识符声明 没有初始化程序,没有存储类说明符或没有 存储类说明符
static
构成暂定 定义。如果翻译单元包含一个或多个暂定 标识符的定义,翻译单元包含 no 对于该标识符的外部定义,那么行为就是完全正确的 好像翻译单元包含一个文件范围声明 标识符,在翻译结束时使用复合类型 单位,初始化程序等于0。
编译(未给出警告):
gcc -g -std=c99 -pedantic-errors -Wall -Wextra main.c a.c
我理解,对于i
变量,有两个是暂定定义,因为main.c
没有“真正的”外部定义,所以它们被合并到这样的定义中。那么a
呢?我是否正确说明,暂定定义不是在多个源文件(即翻译单元)之间“共享”的?
答案 0 :(得分:6)
您的程序错误:它多次定义相同的外部名称。 GNU工具链遵循宽松的链接模型,该模型不会将此标记为错误;它合并了多个定义。但是,这实际上是语言扩展。严格符合ISO C程序不能多次定义名称。
&#34;暂定定义的概念&#34;在一个翻译单元内是纯粹的句法。在翻译单元的最后,任何仍然是暂定的定义都会被固定。#34;作为定义。
调用int i;
的原因&#34;暂定&#34;它是&#34;弱&#34;从某种意义上说。它可以被后来的定义覆盖。如果在翻译单元结束时,它不会变为int i = 0
。
所以例如这是有效的:
int i; /* might become int i = 0 */
int i = 42; /* i is now defined; the tentative definition is replaced */
在这种情况下,i
被理解为定义一次,而不是两次。翻译的单元包含i的单一定义。