首页 > 解决方案 > 执行 #ifdef 和 #ifndef 的 C++ 预处理器

问题描述

所以我目前正在研究使用 OpenCL 的东西。OpenCL 规范为用户提供了一个必须在包含标头 (cl.h) 之前包含的指令

#define CL_TARGET_OPENCL_VERSION 110

这基本上定义了他们想要使用的版本。假设我正在创建一个库,并且我希望我的用户定义它而不是我在我的文件中定义它。我所做的是。

-----main.cpp---
#define CL_TARGET_OPENCL_VERSION 110
#include "library.h"
-------x---------

----library.h-----
#ifdef CL_TARGET_OPENCL_VERSION
#pragma message("def")
#endif

#ifndef CL_TARGET_OPENCL_VERSION
#pragma message("ndef")
#endif
.... include other headers.
--------x---------

编译器同时打印defndef消息。并且 OpenCL 库也会抛出一个未定义的警告。我认为库头会被替换为 main 并且它只会打印def消息。有什么我理解错了吗?

我对预处理器从哪里开始感到特别困惑?如果它main.cpp从上到下开始并从上到下,那么它肯定已经定义了宏。之后它看到包含库,然后它应该只打印def消息,但它会打印两者。

这让我相信预处理器会在将头文件包含在 main 之前扫描头文件?不知道是什么原因。我还保证库头不包含在其他地方。

我注意到的一件有趣的事情是,如果我这样做

-----helper.h---
#define CL_TARGET_OPENCL_VERSION 110    
-------x---------

----library.h-----
#include helper.h    
#ifdef CL_TARGET_OPENCL_VERSION
#pragma message("def")
#endif

#ifndef CL_TARGET_OPENCL_VERSION
#pragma message("ndef")
#endif
.... include other headers.
--------x---------

def它“两次”打印消息。如果有人能解释这一切,我将不胜感激。

编辑:- 我正在编译的文件从一开始main.cpp library.hlibrary.cpp Library.cpp包括在内library.h。也许这个其他cpp导致了问题?

标签: c++c-preprocessor

解决方案


在 C/C++ 程序中,编译器分别处理每个 .c 和 .cpp 文件。

编译器相互独立地构建每个源文件(不是头文件,只有 .c 和 .cpp 文件)(此源文件称为compilation unit)。

因此,当您的 main.cpp 被构建时,编译器会发现#define CL_TARGET_OPENCL_VERSION 110您在 main.cpp 文件顶部添加的,并def发出消息。

但是当编译器构建library.cpp文件时,它没有找到版本定义,所以它发出了ndef消息。

因此,按照这个解释,在最后一种情况下,当您将定义添加到 .h 文件时,编译器会发出def两次消息,一次是针对 main.cpp 文件,一次是针对 library.cpp 文件,这是完全正常的。


现在,问题是您应该在哪里添加定义,以使程序始终如一地构建,并且所有 .cpp 文件的版本都相同。

通常,所有 IDE 都有一些配置页面,您可以在其中为所有项目添加全局定义,这些定义首先“插入”到所有编译单元中。因此,当 IDE 调用编译器时,它会将相同的定义传递给所有编译单元。您应该在此页面中添加此类定义。

在您的 IDE 中(我使用的是 Code::Blocks,v 17.12),您可以在菜单中找到此页面:Project / Build Options

对于每种类型(调试或发布),您必须转到 tab Compiler Settings,然后转到 sub tab #defines。在那里您可以添加全局定义,如果您在调试或发布模式下构建可能会有所不同(当然,如果您在两种模式下设置相同,它们将是相同的)。

一旦您在此处添加了您的定义,请将其从 以及您可能已添加它的任何其他位置中删除,main.cpplibrary.h避免重复。


从关于可移植性的评论中:

你有几个选择:

  • 始终使用 Code::Blocks:这将是最简单的方法,因为您可以将 Code::Blocks 项目与源文件一起传递,并且一切都已经设置好了。

  • Use cmake,这是一个脚本构建系统,您可以在其中设置定义等,其方式与使用 IDE 相同。cmake比 Code::Blocks 使用广泛得多,所以也许它是一个更好的选择。

  • 添加一个新的options.h头文件,在其中设置所有defines.c/.cpp。此设置还有一个额外的好处,即对于不同的系统,仅更改options.h构建的文件可以完全不同。这是 IDE 正在执行的手动设置。它的优点是不依赖外部工具,但缺点是您必须记住将其添加到添加到项目中的所有新 .cpp 文件中。

cmake正如其他人所说,我的建议是 go with 。


推荐阅读