具有多个定义时,extern关键字没有错误

时间:2014-03-14 07:28:45

标签: c++ c linker-errors

我有以下代码段main.c,下面是somefile.h文件

#include "somefile.h"
extern int var = 10000;

int main()
{

    cout << var << endl;
    return 0;
}

和somefile.h包含

int var;

我的问题是,当我执行此代码时,它会产生输出10000,但为什么这不是重新定义错误。因为我认为extern int var = 10000;是定义。此外,如果我在somefile.h中为var分配了一些值,它会给我一个错误,说明重定义是预期的。我正在使用VS 2010.

3 个答案:

答案 0 :(得分:3)

这个问题标记为C和C ++,但这些是不同的语言。我的回答是关于C.

如果您的代码在文件范围包含序列int var; /* ... */ int var = 10000;,那么这在C中是合法的。

int var;被称为暂定定义,它有点像函数的前向声明,但对于变量。如果有变量的后续定义,那么该定义将取代它;否则暂定定义计数,变量将初始化为0

您的extern关键字没有区别,因为除非您专门使用extern关键字,否则无论如何在文件范围定义的变量都是static

但是,如果添加了include somefile.h的第二个翻译单元,则行为未定义。这是因为两个不同的翻译单元都定义了变量var。您的链接器可能会对此进行诊断,但C标准并不要求它。

如果你给somefile.h中的行一个初始值设定项,例如int var = 5000;然后这是编译器必须诊断的多重定义错误。

答案 1 :(得分:2)

我认为OP并没有像他为讨论暂定的定义那样塑造他的榜样。除了语言律师的东西,以及C和C ++之外,也许应该说出基本的想法:

  • 如果您有多个&#34;翻译单元&#34; ,所有这一切都很重要,即单独编译然后在单独步骤中链接在一起的c / cpp文件(这可能发生)如果您使用像VS这样的IDE,可以在幕后使用。
  • 您希望在不具有多个定义的情况下创建已知的多个单元中使用的变量。区别在于&#34;声明&#34; (即已知)与&#34;定义&#34; (即通过创建和创建适当的变量初始化存储)。海关的奥斯卡王尔德宣布&#34;除了他的天才&#34;,但在书籍和对话中定义
  • &#34;制作已知&#34;,即声明,通常通过头文件进行。这只是方便:编译器本身并不了解有关头的任何信息,但会转换连接的代码序列,包括所有头和包含它们的源。使用完全相同的结果可以将头文件复制/粘贴到#include指令所在的c文件中,不涉及任何魔法。理解这一点至关重要。
  • 众所周知,全局变量的声明带有前缀&#34; extern&#34;,表示该定义可能是翻译单元的外部(并记住) ,这里的翻译单元是所有标题和c文件的串联)。没有给出初始值;变量在创建时在别处初始化 (定义可能与我们所见的翻译单元相同。那没关系,extern声明只是多余的,但必须匹配。)
  • 必须创建并初始化Globals,即定义,只需一次,通常在您选择的c / cpp文件中。 该定义不属于头文件。这是因为标题包含在多个c文件中,导致多次尝试创建同一个对象。

我从你的例子中创建了一个带有两个源文件的迷你编程来演示这个想法。第二个c文件包含一个将在main.c中使用的函数。两个c文件都包含相同的头文件。头文件提供了相互信息交换:两个c文件都知道另一个提供的资源(变量,函数)。包括标题还可以确保c文件中的定义与其他人看到的声明匹配。

头文件本身不会创建任何内容。

<强> somefile.h

// make var known to whoever it may concern: 
extern int var;    // declaration, nothing created

extern int computeHalfVar(); // declare a function

<强> halfVar.c

// The header contains the declaration of var
// which is defined in main.c
#include "somefile.h"

int computeHalfVar() { return var/2; }

<强>的main.c

#include <iostream>

// declares computeHalfVar() which we'll use 
#include "somefile.h" 

using namespace std;

// create and initialize var.
// This is the variable everybody else will use.
// The type must match the declaration in the header.
int var = 10000;   

int main()
{
    cout << var << endl;

    // Use a function defined in a different translation unit.
    // The compiler knows the name and signature from the header we included.
    cout << computeHalfVar() << endl;
    return 0;
}

答案 2 :(得分:0)

它不仅仅是重新定义错误。它是&#34; C274:&#39; var&#39; :重新定义;多次初始化&#34;错误。实际上它是多次初始化。如果您查阅Microsoft文档,请明确说明:

标识符不止一次初始化。

http://msdn.microsoft.com/en-us/library/88cc602k%28v=vs.90%29.aspx