user-0 提问: 一个老生常谈的话题："tentative definition"

回复:
user: user-1
content: 引用 12 楼 mymtom 的回复:[quote=引用 7 楼 Feymen 的回复:] 我现在的想法是这样的：     标准中说“在一个翻译单元中，如果出现了同名标识符既有外部又有内部链接属性，这样的行为是未定义的”。也就是说#1和#2中的情况属于未定义行为，编译器有权自行选择num的链接属性，向gcc这样要求严格一点的编译器可能对两种情况都报错，要求不严格的编译器像vc可能就会根据自己对标准的解读进行不同的安排。所以，vc编译#2时将int num;强制为内部链接属性。它这样做的理由可能是考虑到了这一点：int num;这条语句位于static int num;语句的可见作用域之内，这样可以和extern int num;的情形保持一致。     这样理解不知道准确不准确，求各位指教。 赞成楼主的理解！ 但是想说说个人的看法： VS的编译器在这个问题的处理上并不恰当，对于这种在单个编译单元内能通过静态检查就发现的linkage的不一致，编译器起码要发出警告，并指出最后的选择的linkage类型，但是VS编译器却自作主张地自己决定linkage类型（是否有警告我就不得而知了，因为我手边没有VS编译器） 个人这是明显的程序错误，更偏向于gcc的处理方式！[/quote] 标准都是未定义行为了，所以报错没有问题。 另外tentative definition是C语言才有的概念，C++不存在tentative definition，只允许定义一次，所以报错很正常。 另外都什么年代了，不要看C89的标准。C99标准进一步确定了，还是同一章节： 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. 所以static int i;不是临时性定义，你的问题解决了。

user: user-2
content: 不过，既然标准明文规定这是“未定义行为”了，VS的做法也就没有任何问题了，即使编译器其遇到这种情况直接磁盘执行格式化操作 也是应该没问题的。

user: user-3
content: 引用 7 楼 Feymen 的回复:我现在的想法是这样的：     标准中说“在一个翻译单元中，如果出现了同名标识符既有外部又有内部链接属性，这样的行为是未定义的”。也就是说#1和#2中的情况属于未定义行为，编译器有权自行选择num的链接属性，向gcc这样要求严格一点的编译器可能对两种情况都报错，要求不严格的编译器像vc可能就会根据自己对标准的解读进行不同的安排。所以，vc编译#2时将int num;强制为内部链接属性。它这样做的理由可能是考虑到了这一点：int num;这条语句位于static int num;语句的可见作用域之内，这样可以和extern int num;的情形保持一致。     这样理解不知道准确不准确，求各位指教。 赞成楼主的理解！ 但是想说说个人的看法： VS的编译器在这个问题的处理上并不恰当，对于这种在单个编译单元内能通过静态检查就发现的linkage的不一致，编译器起码要发出警告，并指出最后的选择的linkage类型，但是VS编译器却自作主张地自己决定linkage类型（是否有警告我就不得而知了，因为我手边没有VS编译器） 个人这是明显的程序错误，更偏向于gcc的处理方式！

user: user-4

user: user-5
content: 基本上在一个文件不会这样重复声明或定义，用多文件测试比较能看出在说啥...

user: user-3
content: 两个都编译不过嘛！ VS的编译器BUG很多，这时业界公认的！

user: user-6
content: vc 2013, /TC（C 语言）通过， /TP（c++ 语言） 报错。

user: user-0
content: 我现在的想法是这样的：     标准中说“在一个翻译单元中，如果出现了同名标识符既有外部又有内部链接属性，这样的行为是未定义的”。也就是说#1和#2中的情况属于未定义行为，编译器有权自行选择num的链接属性，向gcc这样要求严格一点的编译器可能对两种情况都报错，要求不严格的编译器像vc可能就会根据自己对标准的解读进行不同的安排。所以，vc编译#2时将int num;强制为内部链接属性。它这样做的理由可能是考虑到了这一点：int num;这条语句位于static int num;语句的可见作用域之内，这样可以和extern int num;的情形保持一致。     这样理解不知道准确不准确，求各位指教。

user: user-2
content: 引用 4 楼 Bokutake 的回复:我怀疑这个代码在C和C++编译器编译的结果可能不同。 C++里初始化类的静态变量会有类似2的写法。 恩，C++直接报重定义错误。但是C报出的错误不是这样的。

user: user-7
content: 搜索 C语言的 试探性定义 问题

user: user-1
content: 我怀疑这个代码在C和C++编译器编译的结果可能不同。 C++里初始化类的静态变量会有类似2的写法。

user: user-8
content: 定义的这两句似乎没有意义。。。 在程序结束之后定义。。 好吧，也可以说是在其他函数开始之前。。。

user: user-2
content: 和编译器有关吧，在GCC4.8.2下，这两个都报错

user: user-9
content: static static declarator  When modifying a variable, the static keyword specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends) and initializes it to 0 unless another value is specified. When modifying a variable or function at file scope, the static keyword specifies that the variable or function has internal linkage (its name is not visible from outside the file in which it is declared).   In C++, when modifying a data member in a class declaration, the static keyword specifies that one copy of the member is shared by all the instances of the class. When modifying a member function in a class declaration, the static keyword specifies that the function accesses only static members.  For related information, see auto, extern, and register.  Example  // Example of the static keyword static int i;         // Variable accessible only from this file  static void func();   // Function accessible only from this file  int max_so_far( int curr ) {    static int biggest;    // Variable whose value is retained                           //    between each function call    if( curr > biggest )       biggest = curr;     return biggest; }  // C++ only  class SavingsAccount { public:    static void setInterest( float newValue )  // Member function       { currentRate = newValue; }             //    that accesses                                               //    only static                                               //    members private:    char name[30];    float total;    static float currentRate;    // One copy of this member is                                 //    shared among all instances                                 //    of SavingsAccount };  // Static data members must be initialized at file scope, even //    if private. float SavingsAccount::currentRate = 0.00154;