条件编译的混乱和失败

Conditional compilation confusion and failure

我想用一个通用的*.c文件编译不同的文件。就像我想编译 A.c common.c xor B.c common.c 但我不知道如何实现。

你能告诉我如何让 common.c 使用不同的 headers 而不使用我的文本编辑器每次我想编译时更改 headers 列表

假设我有 3 个文件:A.c、B.c 和 common.c。

A.h 和 B.h 以不同的方式定义枚举 enum {Mon, Tues, Wed...}。该枚举用于 common.c。所以我不能只做 common.c:

#include "A.h"
#include "B.h"

我想到的是使用预处理器指令:

在common.h

#define A 1
#define B 2

在A.c

#define COMPILE_HEADER A

并在 common.c

#if COMPILE_HEADER == A 
#include A.h 
#end

这当然行不通,因为编译器没有访问A.c文件来寻找#define COMPILE_HEADER A

所以你能告诉我如何让 common.c 使用不同的 headers 而不使用我的文本编辑器每次我想编译时更改 headers 列表吗?

解释起来很复杂,但我会试一试。

说明

编译器,例如 gcc,获取提供的输入文件,将头文件包含(实际上只是复制粘贴)到 [=17] 中它们各自的位置(#include 指令所在的位置) =] 文件,然后将文件编译为对象 (*.o) 文件。没有创建可执行文件。 linker 来了,它包含在 gcc 中。它将 *.o 文件和 links 它们放入一个可执行文件中。

问题是,文件是独立编译的,然后 link 在一起。我的意思是,像 int func(int param); 这样的预定义就像对编译器说 "Hey man, don't worry about any usage of func in the code, the linker will care"。然后编译器只是将这个用法作为外部符号保存在相应的*.o文件中,当linker在做他的工作时,他首先找到符号定义(函数实现)的位置,然后指向每当调用 func 时。

尝试在头文件中包含函数定义,然后将其包含在同一项目的 2 个或更多文件中(compiled/linked 在一起)。编译器会说没问题,因为代码是正确的并且生成的代码是有效的。然后,linker 将尝试将它 link 到一个可执行文件中,他将不得不决定它应该 link 到哪个版本的同名参数函数。由于大多数开发人员工具并不真正擅长做出正确的选择,他只会对你大喊大叫 "hey man, you gave me two definitions of same function, what to do now?"。这会导致如下错误:

obj\Release\b.o:b.cpp:(.text+0x0): multiple definition of 'func(int)'
obj\Release\a.o:a.cpp:(.text+0xc): first defined here

在一个项目中有两个 main 怎么样?

obj\Release\b.o:b.cpp:(.text.startup+0x0): multiple definition of 'main'
obj\Release\a.o:a.cpp:(.text.startup+0x0): first defined here

两个文件都能编译,但不能link一起编辑。

头文件旨在包含 class 定义和函数预定义,让您只需编写一次,然后在所有要使用它们的文件之间共享。您始终可以分别为每个文件键入 class 定义(只要它们保持相同)并像在 .h 文件中使用它们一样使用它们,这同样适用于函数预定义。

你的问题来了。您只需编译一个文件,而不是只包含一个文件。您可以使用预处理器技巧来做到这一点,但我不推荐作为解决方案,因为它可以更容易地解决(稍后我会告诉您如何解决)。

TL;DR; (实答无解)

您可以#ifdef / #ifndef 这两个文件,然后在另一个*.c 中定义(或不​​定义)一些值。例如:

A.cpp

#include "t.h"

#ifdef USE_A
int func(int a)
{
    return a + 5;
}
#endif

B.cpp

#include "t.h"

#ifndef USE_A
int func(int a)
{
    return a * 10;
}
#endif

T.h

#ifndef T_H
#define T_H

//Or comment to use B
#define USE_A

int func(int a);

#endif // T_H

main.cpp

#include <iostream>
#include "t.h"

using namespace std;

int main()
{
    cout << func(3);
}

注意 #ifdef/#ifndef#include 之后 ,因此预处理器知道要编译哪一个。此外,不可能(至少我想不出任何方法)在任何 .c 文件中进行定义,因为它们是单独编译的(如上所述)。您可以使用 -D 开关,但这涉及在环境中扰乱构建配置,如果您想这样做,最好尝试下面介绍的第二种解决方案。

更好的答案

每个版本选择一个文件编译。它几乎不取决于您的需要,但基本上您应该编译 a.cpp 或 b.cpp 而不是使用 g++ main.cpp a.cpp b.cpp。如果您正在使用像 Visual Studio 或代码块这样的集成环境,配置管理器允许您决定要包含哪个文件。我的意思是,那些 Debug/Release 下拉菜单可以包含您自己的条目,这将自定义您的项目。 Then, switching between the A.cpp and B.cpp is just a question of choosing appropiate option in the always-visible bar in your environment.

如果您想获得有关如何在 Code::Blocks 或 Visual Studio 上管理配置的更详细教程,请在 Whosebug 上创建适当的问题,我们会立即为您解答:)