用 c++ 编译但不在 c (gcc) 中编译时很复杂
Complicated when compiling in c++ but not in c (gcc)
我在 c++ 中对乘法声明有问题,但在 c 中没有。您可以查看代码以获取更多信息。
文件 main.c
#ifndef VAR
#define VAR
int var;
#endif
int main(){}
文件 其他.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.
由于变量var
的多个定义,您的代码在 C 和 C++ 中形式上都是不正确的。只是这种类型的错误传统上被C编译器作为一种流行的非标准扩展所忽视。这个扩展甚至在C语言规范中被提及
J.5 常见扩展
以下扩展在许多系统中广泛使用,但并非所有人都可移植 实现。[...]
J.5.11 多个外部定义
对象的标识符可能有多个外部定义,带有 或 没有明确使用关键字 extern;如果定义不一致,或超过定义 一个是初始化的,行为是未定义的(6.9.2)。
但从形式上讲,你在 C 语言和C++语言中都有完全相同的多定义错误。要求你的 C 编译器表现得更学究(禁用扩展,如果它有这样的选项),你的 C 编译器也会生成与你的 C++ 编译器相同的错误。
同样,您的代码包含变量var
的多个定义,这在 C 和 C++ 中都是错误的。您的#ifdef
指令根本解决不了任何问题。Preperocessor 指令在这里无法帮助您。预处理器在每个翻译单元中本地独立工作。它无法跨翻译单元查看。
如果要创建一个全局变量(即所有翻译单元共享的同一变量),则需要对该变量进行一个且仅一个定义
int var;
在一个且唯一的翻译单元中。所有其他翻译单位应收到非定义var
声明
extern int var;
后者通常放在头文件中。
如果您需要在每个翻译单元中var
一个单独的自变量,只需在每个翻译单元中将其定义为
static int var;
(尽管在C++中,static
的这种用法现已弃用并被无名称命名空间取代)。
这两个#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++ 会生成强链接器符号,从而导致链接时发生冲突。
编译模块中全局变量的可见性在 C 和 C++ 之间略有不同。
如果这些变量是不同的变量,请将它们括在每个文件的匿名命名空间中。
namespace {
int var;
}
如果它们打算成为 SAME 变量,则其中一个需要一个 extern
decl-specifier,以避免多个定义。
extern int var;
您的#define VAR
在您发布的示例中没有执行任何操作。该定义不会跨编译模块进行。
包含守卫是翻译单元的本地内容。这意味着,当您在一个.cpp
文件中执行#define VAR
时,它不会在任何其他文件中定义。
- 为什么 gcc 编译这个而 msvc 没有
- std::unique_ptr 在 GCC 中工作,但不能在 Visual Studio 中编译
- GCC,CMake,预编译标头和维护依赖项
- GCC 8.3 无法编译 std::bind_front
- Clang不会编译GCC会编译的模板专业化
- 使用交叉工具ng编译gcc时出错
- 编译 GCC-5.0 OS X 狮子 dyld:找不到符号:__ZNKSt11logic_error4whatEv
- 在类中将不完整类型的unique_ptr初始化为 nullptr 时编译 gcc 错误
- 除了 Linux 上的源代码和编译 (GCC) 之外,有没有办法在 Windows 中托管 IDE
- 在 64 位 debian 上编译 GCC 的代码可视化补丁
- 编译gcc 4.6.4中的boost::move
- 模板编译:gcc vs VS2010
- C++ 使用编译器编译"gcc"简单文件
- 如何从php编译GCC
- 在 Visual Studio 中编译 gcc 代码会导致错误 C3646:"__attribute__":未知的覆盖说明符
- 在windows上编译gcc 4.7
- 在Vortex86DX上从头开始构建和编译GCC 5.2.0时出错
- 在编译GCC时出错部分模板专门化,而不是MSVC
- GLM Math lib 编译 GCC 错误
- Synology交叉编译GCC -std=c++0x