#ifdef 标志来区分 gcc 和 g++ 编译器? [复制]
Posted
技术标签:
【中文标题】#ifdef 标志来区分 gcc 和 g++ 编译器? [复制]【英文标题】:#ifdef flag to tell difference between gcc and g++ compilers? [duplicate] 【发布时间】:2014-09-18 18:27:04 【问题描述】:gcc 将 C 程序编译为 C,将 C++ 程序编译为 C++,因此需要在 C++ 中声明“extern "C"”。而 g++ 将 C 程序编译为 C++,将 C++ 程序编译为 C++,因此要求在 C++ 中不得使用“extern "C"”声明。
在没有任何输入的情况下检查标准标志,两者都
g++ -E -dM - </dev/null
gcc -E -dM - </dev/null
给出相同的结果。
__GNUG__ is equivalent to testing (__GNUC__ && __cplusplus)
这将再次不区分 gcc 和 g++在 C++ 源代码列表中。
有什么魔力
#ifndef __MAGIC_G++_INCLUDE_FLAG_BUT_NOT_GCC__
环绕 extern "C" 声明?谢谢。
编辑:我意识到这是一个相当深奥的案例。测试需要在 compiler 风格上完成,而不是在 source code 风格上。在这两种情况下,测试都是在 C++ 源代码列表中执行的(这就是我提到 GNUG 不足的原因)。澄清一下,对于测试 main.cpp:
#include <iostream>
int
main( int argc, char **argv )
#ifdef __cplusplus <<<< FIX THIS ONE
std::cout << "I was compiled using g++" << std::endl;
#else
std::cout << "I was compiled using gcc" << std::endl;
#endif
使用任一编译时
g++ main.cpp
或
gcc main.cpp -lstdc++
在这两种情况下,它似乎都错误地给出了“我是使用 g++ 编译的”作为输出。所以看起来 cplusplus 不是在这种情况下使用的正确标志。我错了吗?或者正确的标志是什么?
编辑 2: 多谢你们。这是给你的一个例子。大型遗留系统“Alpha”主要是用 C 编写的,带有少量 C++,并使用大型遗留源包“Charlie”,用 C++ 编写。它使用 g++ 系统编译和链接,并要求 Charlie 的头文件中没有外部“C”定义,否则它拒绝链接。大型遗留系统“Bravo”主要是用 C 编写的,带有一点 C++,并且还使用相同的遗留源包 Charlie,用 C++ 编写。它使用 gcc 系统编译和链接,并要求 Charlie 的头文件中必须有 extern "C" 定义,否则它拒绝链接。新系统“Delta”、“Echo”和“Foxtrot”也想重用来自 Charlie 的部分源代码,要使用的编译器不确定。正确的答案是用
一劳永逸地破解查理的标题#ifndef __MAGIC_G++_INCLUDE_FLAG_BUT_NOT_GCC__
extern "C"
#endif
...
declarations of code
...
#ifndef __MAGIC_G++_INCLUDE_FLAG_BUT_NOT_GCC__
#endif
然后完成它。否则总会有链接问题。是的,当然可以在这种特殊情况下编译两组库,一组在 C 下,另一组在 C++ 约定下,然后要求您将这个特定的库用于这种特殊的链接风格。或者我可以想出两组标题。在这个例子中,其中任何一个都是不优雅的,并且会继续导致问题;还有其他情况。至于 g++ 和 gcc 都在后台使用相同的编译器的评论,所以它可能并不重要,遗憾的是,它确实如此。当错误的 'extern "C"' 教条包含/不包含时,包作为一个整体拒绝链接。是的,还有其他方法可以解决一般问题,但这是一个简单的问题。要么存在这样的标志,要么已知不存在,或者无法确定答案。我不知道,我自己。
【问题讨论】:
您是否有理由需要知道这一点?是您的构建脚本/进程/等。不是 gcc/g++ 编译器的标准? 您应该使用gcc
命令编译 C 源代码并使用 g++
命令编译 C++ 源文件。你这样做有什么原因吗?
__cplusplus
是为 C++ 定义的,但不是为 C 定义的。无论如何,两个驱动程序(gcc
和 g++
是真实编译器的包装器)都可用于编译 C 和 C++ 源代码,尽管它们默认使用不同的标志,但分别最适合 C 和 C++。
调用 gcc 或 g++ 都没有关系。如果 gcc 确定源文件是 C++,则与 g++ 将运行的编译器相同,即二进制 cc1plus 是实际运行以编译源代码的编译器。如果您使用 gcc 编译 和 链接,那么在链接阶段虽然有所不同 - 但在编译阶段则没有。如果您解释您要解决的实际问题,这可能会有所帮助。
您的编辑说明了为什么这个问题没有什么意义——因为文件被称为main.cpp
,无论您在命令上调用g++
还是gcc
,g++ 都将用于编译它行(在后一种情况下,gcc
只会为您调用 g++
),因此您总是会得到“使用 g++ 编译”。如果你想强制使用 gcc 而不管名称,你可以使用命令行参数-x c
,但是它根本不会编译,因为它不是有效的 C 代码。
【参考方案1】:
标准技术是检查预处理器符号__cplusplus
是否已定义:
#ifdef __cplusplus
extern "C"
#endif
/* declarations here */
#ifdef __cplusplus
#endif
【讨论】:
很遗憾,这并不能解决所提出的问题,请参阅编辑。谢谢。 这是在 gcc 下填充 C 代码以使其适合 C 或 C++ 的标准一阶方法。它看起来并没有解决我正在攻击的 C++ 问题。 当源代码是 C 语言而不是 C++ 时,它确实能正确区分两个编译器。也就是说,如果我使用的是 main.c 而不是 main.cpp,则此标志将说明 gcc 和 g++ 之间的区别。但是,由于 extern "C" 指令仅在 C++ 中有用,因此尚不清楚这如何解决一般问题。 作为一个失败的例子,从 C 中的子例程 child.c 开始,由父 main.cpp 调用。通过在定义周围插入此代码来修改其头文件 child.h。这实际上适用于 gcc 编译器/链接器。但是,在使用 g++ 时,编译器会在编译时悄悄地将子对象的表示形式更改为 C++ 样式。但是父级仍然期待 C 样式,因为包含的标头指定了 extern "C"。结果,在 g++ 下,最终链接失败。我认为,在使用 g++ 编译器/链接器时,extern "C" 应该被省略掉。以上是关于#ifdef 标志来区分 gcc 和 g++ 编译器? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
用于 GCC/G++ 的宏来区分 Linux 和 Mac OSX?