#if vs #ifndef vs #ifdef

Posted

技术标签:

【中文标题】#if vs #ifndef vs #ifdef【英文标题】: 【发布时间】:2016-05-07 19:38:56 【问题描述】:

我的问题首先是理解#ifndef#ifdef。我还想了解#if#ifndef#ifdef 之间的区别。我知道#if 基本上是一个 if 语句。例如:

#include<iostream>
#define LINUX_GRAPHICS 011x101

int main()
 long Compare = LINUX_GRAPHICS;
 #if Compare == LINUX_GRAPHICS
   std::cout << "True" << std::endl;
 #endif

但是其他的,虽然我读过他们,但我无法理解。它们看起来也非常相似,但我怀疑它们的工作方式相似。非常感谢您的帮助。

【问题讨论】:

您似乎想用宏替换代码。为什么?不要那样做。 “我理解#if 基本上是一个 if 语句”——甚至没有关闭。您发布的代码根本没有意义。您需要阅读预处理器的基础知识,然后就您难以理解的具体细节提出问题。 如果你从 C++ 开始,你应该尽量少了解预处理指令... 通过阅读 C++ 书籍来学习 C++,而不是在文本编辑器中胡乱猜测,然后在一个小时后放弃并要求我们为您完成所有学习。 我想说的是,预处理器的使用应该限制在#include,以及像#define#ifdef#ifndef,最终@ 987654332@。其余的,你真的不需要了。这就是为什么我建议尽可能少地了解 ;-) 【参考方案1】:

宏由预处理器扩展,该预处理器在运行时对变量的值一无所知。它只是关于文本替换(或比较预处理器已知的符号)。你的线路

#if Compare == LINUX_GRAPHICS

将扩展为

#if Compare == 011x101

并且由于“比较”与“011x101”不同,它的计算结果为假。实际上,我什至不能 100% 确定这一点,但重点是:您将预处理器指令与在运行时评估的变量混合在一起。那是无稽之谈。预处理器指令不能代替 C++ 语句。

对于大多数传统的宏用例,现在有更好的方法。如果你真的不需要使用宏,最好不要使用它们。它使阅读代码变得非常困难(例如,我不明白代码中的宏是如何工作的,除非我真的需要它,否则我不想知道:P)并且宏还有其他问题可能导致非常困难查找程序中的错误。在使用宏之前,我建议您首先考虑是否有更自然的 C++ 方式来实现相同的目标。

PS:

#ifdef SYMBOL
    ifdef = "if defined"
    this part of the code is excluded before the compiler even sees it
    if SYMBOL is not defined (via #define)
#endif

#ifndef SYMBOL
    ifndef = "if not defined"
    this part of the code is excluded before the compiler even sees it
    if SYMBOL is defined (via #define)
#endif

我写“排除”是为了强调它对代码可读性的不良影响。如果你在普通代码块中过度使用#ifdef#ifndef,将会非常难以阅读。

【讨论】:

#ifdef 和 #ifndef tobi 怎么样? @Dsafds 这些检查预处理器符号是否存在,与它的值无关(实际上可以为空)。 @Dsafds 我添加了解释 @tobi303 当我看到你的解释时,我想到了两个问题。第一:我看不出#ifdef#ifndef 之间有任何区别。第二:在有条件的 preproccecor 指令中,你只能访问由#define定义的preproccecor“变量”/?? tobi303:严格来说,预处理器通过递归扩展所有宏并将所有非宏符号替换为0不是什么都没有)来工作。然后它尝试将结果评估为仅具有整数常量的算术表达式。结果是#if NOT_DEFINED == ALSO_NOT_DEFINED会成功;这是一个经典的预处理器陷阱。【参考方案2】:

#ifCompare 或其包含的值没有任何概念,因此它可能不会按照您的意愿行事。

记住预处理器会进行纯文本替换。

#if 看到的语句将扩展为

#if Compare == 011x101

并被扩展为

#if 0 == 011x101

在预处理阶段肯定不会产生true


#ifdef#ifndef 指令检查预处理器符号是否完全是#define'd,或者使用那个(-D<preprocessor-symbol>)。 这些不关心预处理器符号是否带有空值或其他东西。一个简单的

#define MY_CONDITION

-DMY_CONDITION

足以满足

#ifdef MY_CONDITION

扩展随后出现的文本(或使用#ifndef 隐藏它)。


Compare 声明不是预处理器符号,也不能与#ifdef#ifndef 一起合理使用。

【讨论】:

所以你的解释中出现了一个问题。预处理阶段是像编译“东西”的第一阶段吗?还是在 main 之前,所以 preprocecor 条件看不到定义为“非 preproccecor”的实际变量(Wild English there woah sorry)。 @dsafds:他说的是你可以在#ifdef(或#ifndef)中使用任何你喜欢的符号。这是真的:要么符号是#define'd,在这种情况下#ifdef 成功并且#ifndef 失败,或者它不是#define'd,在这种情况下#ifdef 失败并且#ifndef成功。该符号稍后是否会被程序声明完全无关紧要。 好吧,我运行了这段代码:github.com/amanuel2/ng-forum/blob/master/***/… 我创建了,看来你赢了。对不起 tobi,但这纯粹是运气。 @Dsafds “但这纯粹是运气”请注意,您错过了seed()您的随机引擎。我会永远赢,是不是有点不公平? 通常我对人们使用 srand() 错误的帖子感到有点厌烦,但这次我不介意 ;)【参考方案3】:

#if 是预处理器if。它只能处理预处理器的东西,这些预处理器基本上是预处理器宏(类似于函数或类似常量)和带有一些简单整数文字算术的 C 标记。

#ifdef SOMETHING#if defined(SOMETHING) 相同,并且 #ifndef SOMETHING#if !defined(SOMETHING) 相同。 defined 是一个特殊的预处理器运算符,它允许您测试 SOMETHING 是否是已定义的宏。这些基本上是最常见用途或预处理器条件的快捷方式——测试是否定义了某些宏。

您可以在 gcc 预处理器上找到详细的手册(约 80 页) https://gcc.gnu.org/onlinedocs/.

【讨论】:

【参考方案4】:

预处理器#ifdef 和#ifndef 的含义如下:在您的示例中,您使用#define 将名为LINUX_GRAPHICS 的常量变量设置为等于011x101。因此,稍后在您的程序中,您可能希望检查此变量是否已定义。然后你使用#ifdef,当你想检查这个变量是否被定义时,如果没有,则使用#ifndef。我希望我能帮助你。

【讨论】:

一个“常量变量”?? 是的,一个常量变量 某事不能同时是“常量”和“变量”。【参考方案5】:

基本上,预处理器会进行文本替换。然后编译器将程序编译成机器码。然后CPU执行机器指令。这意味着您不能使用预处理器 #if 代替运算符 if:一个执行文本替换,而第二个为 CPU 生成分支代码。

因此,诸如#if#ifdef#ifndef 之类的预处理器指令用于基于某些“元输入”生成(一点)不同程序的“半自动模式”。实际上,您始终可以自己进行这些替换,并在没有任何预处理器指令的情况下获得工作的 C/C++ 程序。此外,编译器通常有一个命令行开关,它只输出预处理程序,即没有任何#if 指令。尝试使用它,您应该会了解这些指令的作用。

#ifdef XXX#if defined(XXX) 相同,其中defined(XXX) 是内置的仅预处理器函数,当另一个预处理器指令#define 在程序文本中定义标识符XXX 时为真。而#ifndef XXX 就是#if !defined(XXX)

【讨论】:

以上是关于#if vs #ifndef vs #ifdef的主要内容,如果未能解决你的问题,请参考以下文章

可以在 #ifndef ... #endif 等预处理器指令块中的 VS2008 中启用智能感知吗

VS2008(C++)-控制台项目中LNK2005错误的问题

VS编译器如何调用动态链接库文件

ActiveX 插件导致 ASSERT 在 VS2008 中的应用程序退出时失败

Haskell中的Guards vs. if-then-else vs. case

在if语句之后返回vs啥都不做[重复]