C-ifdef的替代方案

C-ifdef的替代方案,c,c-preprocessor,conditional-compilation,hardcoded,C,C Preprocessor,Conditional Compilation,Hardcoded,我正试图精简大量遗留C代码,即使在今天,在进行构建之前,维护它的家伙会获取一个源文件,并根据各种类型的环境在编译之前手动修改以下部分 下面是一个例子,但问题是。我对我的C有些生疏,但我确实记得不鼓励使用#ifdef。你们能提供更好的选择吗?此外,我认为其中一些(如果不是全部)可以设置为环境变量或作为参数传入,如果是这样的话,定义它们然后从源代码访问的好方法是什么 下面是我正在处理的代码片段 #define DAN NO #define UNIX NO #defi

我正试图精简大量遗留C代码,即使在今天,在进行构建之前,维护它的家伙会获取一个源文件,并根据各种类型的环境在编译之前手动修改以下部分

下面是一个例子,但问题是。我对我的C有些生疏,但我确实记得不鼓励使用#ifdef。你们能提供更好的选择吗?此外,我认为其中一些(如果不是全部)可以设置为环境变量或作为参数传入,如果是这样的话,定义它们然后从源代码访问的好方法是什么

下面是我正在处理的代码片段

#define DAN          NO
#define UNIX         NO
#define LINUX        YES
#define WINDOWS_ES   NO
#define WINDOWS_RB   NO

/* Later in the code */
#if ((DAN==1) || (UNIX==YES))
#include <sys/param.h>
#endif

#if ((WINDOWS_ES==YES) || (WINDOWS_RB==YES) || (WINDOWS_TIES==YES))
#include <param.h>
#include <io.h>
#include <ctype.h>
#endif

/* And totally insane harcoded paths */
#if (DAN==YES)
char MasterSkipFile[MAXSTR] = "/home/dp120728/tools/testarea/test/MasterSkipFile";
#endif

#if (UNIX==YES)
char MasterSkipFile[MAXSTR] = "/home/tregrp/tre1/tretools/MasterSkipFile";
#endif

#if (LINUX==YES)
char MasterSkipFile[MAXSTR] = "/ptehome/tregrp/tre1/tretools/MasterSkipFile";
#endif

/* So on for every platform and combination */
#定义数据编号
#定义UNIX编号
#定义LINUX是
#定义WINDOWS\u ES NO
#定义WINDOWS\u RB NO
/*代码的后面部分*/
#如果((DAN==1)| |(UNIX==YES))
#包括
#恩迪夫
#如果((WINDOWS_ES==是)| |(WINDOWS_RB==是)| |(WINDOWS_TIES==是))
#包括
#包括
#包括
#恩迪夫
/*而且完全是疯了*/
#如果(DAN==是)
char MasterSkipFile[MAXSTR]=“/home/dp120728/tools/testrea/test/MasterSkipFile”;
#恩迪夫
#如果(UNIX==是)
char MasterSkipFile[MAXSTR]=“/home/tregrp/tre1/tretools/MasterSkipFile”;
#恩迪夫
#如果(LINUX==是)
char MasterSkipFile[MAXSTR]=“/ptehome/tregrp/tre1/tretools/MasterSkipFile”;
#恩迪夫
/*每个平台和组合都是如此*/

当然,您可以在命令行上传递
-DWHATEVER
。或者
-DWHATEVER\u ELSE=NO
,等等。对于路径,您可以执行以下操作

char MasterSkipFile[MAXSTR] = SOME_COMMAND_LINE_DEFINITION;
然后通过

-DSOME_COMMAND_LINE_DEFINITION="/home/whatever/directory/filename"

在命令行上。

使用以下命令更明智:

#if SOMETHING
。。从一个平台到另一个平台,以避免混淆损坏的预处理器。然而,任何现代编译器最终都应该有效地论证您的情况。如果您提供更多关于平台、编译器和预处理器的详细信息,您可能会得到更简洁的答案


考虑到操作系统和其中的变体过多,条件编译是一种必要的邪恶。if、ifdef等显然不是对预处理器的滥用,只是按预期使用它。

我们过去常做的一件事是生成一个包含这些定义的
.h
文件,并用脚本生成它。这帮助我们摆脱了很多脆弱的假设和假设

你需要小心你放在那里的东西,但是机器特定的参数是很好的候选者-这就是autoconf/automake的工作方式

编辑:在您的情况下,一个示例是使用生成的
.h
文件定义
INCLUDE_SYS_PARAM
INCLUDE_PARAM
,在代码本身中使用:

#ifdef INCLUDE_SYS_PARAM
#include <sys/param.h>
#endif

#ifdef INCLUDE_PARAM
#include <param.h>
#endif
#ifdef包含系统参数
#包括
#恩迪夫
#ifdef包含参数
#包括
#恩迪夫

使移植到新平台变得更加容易-新平台的存在不会慢慢进入代码,只会进入生成的
.h
文件。

我首选的方法是让构建系统进行操作系统检测。复杂情况下,您可能希望将特定于机器的内容隔离到单个源文件中,并为不同的操作系统提供完全不同的源文件

因此,在本例中,您将在该文件中包含一个
#include“OS_Specific.h”
。您为这个平台输入了不同的include和MasterSkipFile的定义。您可以通过在编译器命令行上指定不同的
-I
(包括路径目录)在它们之间进行选择


这样做的好处是,试图找出代码(可能是调试)的人不必费力地(也可能被他们甚至没有运行的平台的幻影代码误导。)

我见过构建系统时,大多数源文件都是这样开始的:

#include PLATFORM_CONFIG
#include BUILD_CONFIG
编译器的开始是:

cc -DPLATFORM_CONFIG="linuxconfig.h" -DBUILD_CONFIG="importonlyconfig.h"
(这可能需要反斜杠转义)

这使您可以将一组文件中的平台设置与另一组文件中的配置设置分开。平台设置管理处理可能不存在于一个平台上或格式不正确的库调用,以及定义重要的大小相关类型,这些类型是特定于平台的。生成设置处理在输出中启用的功能。

特定于平台的配置标题 我将有一个系统来将特定于平台的配置生成到所有构建中使用的头文件中。AutoConf名称为'config.h';您可以看到“platform.h”或“porting.h”或“port.h”或主题的其他变体。此文件包含正在构建的平台所需的信息。您可以通过将版本控制的平台特定变量复制到标准名称来生成该文件。您可以使用链接而不是复制。或者,您可以运行配置脚本,根据脚本在计算机上找到的内容确定其内容

配置参数的默认值 守则:

#if (DAN==YES)
char MasterSkipFile[MAXSTR] = "/home/dp120728/tools/testarea/MasterSkipFile";
#endif

#if (UNIX==YES)
char MasterSkipFile[MAXSTR] = "/home/tregrp/tre1/tretools/MasterSkipFile";
#endif

#if (LINUX==YES)
char MasterSkipFile[MAXSTR] = "/ptehome/tregrp/tre1/tretools/MasterSkipFile";
#endif
最好由以下内容取代:

#ifndef MASTER_SKIP_FILE_PATH
#define MASTER_SKIP_FILE_PATH "/opt/tretools/MasterSkipFile"
#endif

const char MasterSkipFile[] = MASTER_SKIP_FILE_PATH;
希望在不同位置构建的用户可以通过以下方式设置位置:

-DMASTER_SKIP_FILE_PATH='"/ptehome/tregtp/tre1/tretools/PinkElephant"'
注意单引号和双引号的使用;尽量避免在命令行中使用反斜杠进行此操作。您可以对各种事情使用类似的默认机制:

#ifndef DEFAULTABLE_PARAMETER
#define DEFAULTABLE_PARAMETER default_value
#endif
如果你选择好你的默认值,这可以节省很多能量

可重定位软件 我不确定只能安装在一个位置的软件的设计。在我的书中,您需要能够在新的2.1版本的同时在机器上安装产品的旧版本1.12,并且它们应该能够独立运行。硬编码的路径名会破坏这一点

按功能而非平台参数化 AutoConf工具和一般替代系统之间的关键区别在于,配置是基于功能完成的,而不是在平台上完成的。您可以参数化代码以标识要使用的功能。这一点很关键,因为功能往往看起来很简单
#if defined(SUN4) || defined(SOLARIS_2) || defined(HP_UX) || \
    defined(LINUX) || defined(PYRAMID) || defined(SEQUENT) || \
    defined(SEQUENT40) || defined(NCR) ...
#include <sys/types.h>
#endif
#ifdef INCLUDE_SYS_TYPES_H
#include <sys/types.h>
#endif
#define INCLUDE_SYS_TYPES_H
KVLOCKING
B1SECURITY
C2SECURITY
DYNAMICLOCKS
#ifdef KVLOCKING
...KVLOCKING stuff...
#else
...non-KVLOCKING stuff...
#endif
extern char MasterSkipFile[];