【问题标题】:Concatenate and stringize macro values for #include为#include 连接和字符串化宏值
【发布时间】:2023-04-01 06:21:01
【问题描述】:

我正在尝试从多个宏/值创建一个字符串以用于#include。我这样做是为了清理简单状态系统中初始状态的一些代码。

我有 2 个默认的、可重新定义的宏(如果未定义,则有一个默认值)

   #define DEFAULT_STATE          StateName    // name of class
   #define DEFAULT_STATE_LOCATION states/      // location of header file from root

root 中的文件 4 文件夹中使用了包含指令,因此包含应该如下所示

#include "../../../../states/StateName.h"

基于上面的例子。

所以我想从 4 个值中定义一个宏。

../../../../
DEFAULT_STATE_LOCATION
DEFAULT_STATE
.h

进入一些宏,比如DEFAULT_STATE_INCLUDE

所以我可以说

#include #DEFAULT_STATE_INCLUDE
(to stringize the value for quotes)

这样我可以在前缀头中更改默认状态和默认状态的头文件根路径,并且使用#include的源不必更新,我可以省略每次重新定义的常量。

我没有在DEFAULT_STATE 宏中包含.h,因为我使用相同的宏来创建默认状态的实例。

我尝试过使用串联 ## 和 stringize 运算符,以及我在网上找到的一些技巧,但没有任何效果。

如果需要,我可以在自己的宏中定义../../../../.h

只是简单

    #define DEFAULT_STATE_INCLUDE ../../../../ ## DEFAULT_STATE_LOCATION ## DEFAULT_STATE ## .h
    #include #DEFAULT_STATE_INCLUDE

给出大量错误。

感谢任何帮助。 谢谢

【问题讨论】:

  • 这通常是构建系统定义包含路径的角色

标签: c++ objective-c c xcode gcc


【解决方案1】:

请注意,C99 标准第 6.10.2 节“源文件包含”中的脚注 143 说:

143) 请注意,相邻的字符串文字不会连接成单个字符串文字(参见翻译 5.1.1.2) 中的阶段;因此,导致两个字符串文字的扩展是无效指令。

因此,任何字符串连接都必须在源代码之外完成。与## 的令牌连接不是一种选择;用于构建标识符,而您加入的标头名称的位不是标识符。

我认为你应该简单地使用类似的东西:

#ifndef STATE_HEADER
#define STATE_HEADER "states/StateName.h"
#endif
#include STATE_HEADER

并将其留给构建系统,而不是源代码,以确定 -I../../../.. 是否需要作为编译器的选项。

【讨论】:

    【解决方案2】:

    你最好通过 -I 选项将包含目录传递给 gcc

    -I../../../..
    

    来自 gcc 手册页:

    -I dir
    Add the directory dir to the list of directories to be searched for header files.
    

    【讨论】:

      【解决方案3】:

      这似乎相关:Computed Includes

      我对此的理解是,#define 宏必须包含 "(引号)字符,并且您不能依赖字符串化或连接运算符为您执行此操作。

      【讨论】:

      • 不完全是:您可以依赖字符串化和连接运算符,并且可以使用<> 形式,只是所有这些都很难正确使用。对于该页面上未提及的示例,#include HEADER(errno) 其中HEADER(x) 定义为<x.h> 是有效的——只要errno 尚未定义为宏。如果是这样,那么事情就会破裂,相当糟糕。
      • 如果 errno 是一个宏,你将如何让它工作?如果我能做到这一点并且只使用 2 个参数来传递位置和名称宏,这将正常工作
      • @user1137704 简短回答:你不能。更长的答案:当 errno 作为单独的标记出现时,防止宏扩展的唯一方法是直接使用 stringize 运算符,而无需进行第二次宏扩展。但在这种情况下,您只会得到"errno",这对您的目的毫无用处。最后,请参阅简短答案。
      猜你喜欢
      • 2018-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-08
      • 1970-01-01
      • 2017-08-27
      • 2011-07-12
      相关资源
      最近更新 更多