c++ - 执行 #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---------
编译器同时打印def
和ndef
消息。并且 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.h
就library.cpp
Library.cpp
包括在内library.h
。也许这个其他cpp导致了问题?
解决方案
在 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.cpp
以library.h
避免重复。
从关于可移植性的评论中:
你有几个选择:
始终使用 Code::Blocks:这将是最简单的方法,因为您可以将 Code::Blocks 项目与源文件一起传递,并且一切都已经设置好了。
Use
cmake
,这是一个脚本构建系统,您可以在其中设置定义等,其方式与使用 IDE 相同。cmake
比 Code::Blocks 使用广泛得多,所以也许它是一个更好的选择。添加一个新的
options.h
头文件,在其中设置所有defines
.c/.cpp。此设置还有一个额外的好处,即对于不同的系统,仅更改options.h
构建的文件可以完全不同。这是 IDE 正在执行的手动设置。它的优点是不依赖外部工具,但缺点是您必须记住将其添加到添加到项目中的所有新 .cpp 文件中。
cmake
正如其他人所说,我的建议是 go with 。
推荐阅读
- docker - IDE 如何索引 docker 容器中的库文件夹?
- gitlab - 为什么我的管道作业没有在 GitLab UI 中链接在一起
- php - 无法通过 PHP 邮件功能发送邮件
- python - 任何人都可以暗示一种方法来回忆我在 kivy 中的迭代标签吗?
- flutter - 如何创造安全区域的条件?
- c# - $http 将 AngularJs 放入 WebApi 调用,将对象的一个属性作为 null
- postgresql - PostgreSQL - 带有 where 子句的递归查询
- javascript - 我有一个数字数组。问题是从中获取一组独特的对象
- azure - Azure 管道显示 OSError:[Errno 22] 无效参数:
- android - 由于 AndroidManifest.xml 导致的编译错误/任务“:app:processDebugManifest”的执行失败