在c ++中编译但在c(gcc)中编译时复杂

时间:2012-08-08 23:05:01

标签: c++ c gcc compiler-errors g++

我在c ++中有乘法声明的问题,但在c中却没有。 您可以查看代码以获取更多信息。

file main.c

#ifndef VAR
#define VAR
int var;
#endif
int main(){}

file other.c

#ifndef VAR
#define VAR
int var;
#endif

使用gcc编译

gcc main.c other.c
>> success

使用g ++编译

g++ main.c other.c
Output:
/tmp/ccbd0ACf.o:(.bss+0x0): multiple definition of `var'
/tmp/cc8dweC0.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

我的gcc和g ++版本:

gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

g++ --version
g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

4 个答案:

答案 0 :(得分:12)

由于变量var的多个定义,您的代码在C和C ++中都是正式错误的。只是这种类型的错误传统上被C编译器忽略为一种流行的非标准扩展。这个扩展甚至在C语言规范中提到

  

J.5常见扩展程序

     

以下扩展在许多系统中被广泛使用,但并不是所有系统都可移植   实现。 [...]

     

J.5.11多个外部定义

     

对象的标识符可能有多个外部定义,用或   没有明确使用关键字extern;如果定义不同意或不同   一个被初始化,行为未定义(6.9.2)。

但正式地说,C和C ++语言中的多重定义错误完全相同。要求你的C编译器更迂腐(禁用扩展,如果它有一个选项),你的C编译器也会产生与你的C ++编译器相同的错误。

同样,您的代码包含变量var的多个定义,这在C和C ++中都是错误的。你的#ifdef指令根本没有解决任何问题。 Preperocessor指令在这里无法帮助你。预处理器在每个翻译单元中本地和独立地工作。它无法看到翻译单元。

如果要创建全局变量(即所有翻译单元共享的相同变量),则需要对该变量进行一个且只有一个定义 / p>

int var;

在一个且只有一个翻译单元中。所有其他翻译单元应接收var

的非定义声明
extern int var;

后者通常放在头文件中。

如果您需要在每个翻译单元中使用单独的变量var,只需在每个翻译单元中将其定义为

static int var;

(尽管在C ++中,static的这种用法现在已被弃用并被无名命名空间取代。)

答案 1 :(得分:0)

两个#define指令彼此无关,因为它们位于不同的翻译单元(即源文件)中。编译器完全隔离处理两个源文件,因此defined(VAR)始终为false,并且始终包含#ifndef的内容。

如果您的意思是在多个源文件之间共享一个变量,有一种简单的方法可以解决它:在一个源文件中定义,并且声明它在另一个:

// other.cpp
int var;        // Definition.

// main.cpp
extern int var; // Declaration.

链接时,这些将引用相同的var。更好的是,在标题中声明变量:

// other.h
extern int var;

然后需要var的文件可以只包含标题:

// main.cpp
#include "other.h"

您在C和C ++之间观察到的差异与C与C ++中全局声明的标识符的处理有关。在C中,任何数量的暂定定义(没有存储类说明符和没有初始化程序)可以由链接器合并到一个符号中 - 只要该符号的所有实际定义最终都具有相同的符号联系和存储类。这是使用链接符号完成的。

但是,C ++没有暂定定义的概念,并将没有存储类说明符的外部声明视为定义。因此,G ++生成链接器符号,导致链接时发生冲突。

答案 2 :(得分:-1)

编译模块中全局变量的可见性在C和C ++之间略有不同。

如果这些变量是不同的变量,请将它们包含在每个文件的匿名命名空间中。

namespace {
 int var;
}

如果它们是SAME变量,则其中一个需要extern decl-specifier,以避免多个定义。

extern int var;

您的#define VAR在您发布的示例中没有做任何事情。该定义不在编译模块中进行。

答案 3 :(得分:-1)

包含警卫是翻译单位的当地人。这意味着当您在一个#define VAR文件中执行.cpp时,它不会在任何其他文件中定义。