【问题标题】:How to rename a C preprocessor macro?如何重命名 C 预处理器宏?
【发布时间】:2016-01-13 00:44:01
【问题描述】:

考虑一个(只读的第三方)标头lib.h

#define XYZ 42

在源文件中,我想将单词XYZ 用于不相关的目的,并且不希望用42 进行替换。但是,在同一个源文件中,出于其他目的,我也确实想从 lib.h 访问值 42 而不对其进行硬编码。如何将宏从XYZ重命名LIB_XYZ

以下内容不起作用,因为预处理器在进行 LIB_XYZ 替换时需要 XYZ,但 XYZ 尚未定义:

#include "lib.h"
#define LIB_XYZ XYZ
#undef XYZ

有没有办法诱使预处理器在XYZ 丢失之前将LIB_XYZ 扩展为最终值?

【问题讨论】:

  • 我认为你被卡住了,如果你想从第三方头文件中获取 LIB_XYZ 的定义,并且除了 C 编译器之外不想使用任何东西。如果我必须这样做,我可能会编写一个脚本来将 lib.h 转换为 our_lib.h,并修改选定的#define,使我的代码包含 our_lib.h,并使用一个 makefile 来使正确的事情发生,如果 lib .h 改变了。
  • 也许this 可以提供帮助。

标签: c macros


【解决方案1】:

至少,我不知道预处理器没有。

但是,对于示例中已知类型的简单常量,有一种解决方法。

#include <stdio.h>

// <xyz.h>

#define XYZ 42

// </xyz.h>

enum xyz_constants
{
  LIB_XYZ = XYZ,
};

#undef XYZ

#define XYZ 27

int
main()
{
  printf("old value: %d, new value: %d\n", LIB_XYZ, XYZ);
  return 0;
}

没有显示来自stdio.h的绒毛,这段代码被预处理为以下。

enum xyz_constants
{
  LIB_XYZ = 42,
};

int
main()
{
  printf("old value: %d, new value: %d\n", LIB_XYZ, 27);
  return 0;
}

您可以在一定程度上将此扩展到其他数据类型和某些类似函数的宏,但当然有限制。

无论如何,您为什么需要特定标识符XYZ?您不能为您的宏使用不同的名称吗?

【讨论】:

  • 枚举技巧太棒了!谢谢!原因:XYZ 是我通过串联构建的另一个第三方宏的子字符串,并且串联宏是通用的(适用于 XYZ 或 ABC 或其他),所以坚持使用 XYZ。
  • 这个解决方案救了我:)
  • 在一般情况下,涉及#undef XYZ 的解决方案可能不起作用。该库可以在其宏的替换文本中引用XYZ;这些宏将打破XYZ 未定义或重新定义为其他内容。如果你知道这些宏是什么并且可以避免它们,那么它是可行的。
【解决方案2】:

如果来自lib.hXYZ 是一个数字 [或各种常量],您可以使用enum

enum { LIB_XYZ = XYZ };
#undef XYZ

如果XYZ 不是上述,您必须创建(例如)myxyz.c 确实包含lib.h 并在那里使用XYZ(其他文件可能包括xyz.h)

不同之处在于#define LIB_XYZ XYZ不会在该行被解析,只有当你以后使用它时,如:

foo(LIB_XYZ);

因为你已经#undef'edXYZ,所以这行不通。

【讨论】:

    【解决方案3】:

    预处理器符号是一个名称。没有预处理指令可以更改名称本身,同时保留内容。例如,给定以下任一条件:

    #define FOO 42
    

    #define FOO(x, y)  x ## y (
    

    如果不重复这些定义,就无法定义具有相同内容的名为BAR 的宏。也就是说,没有像这样的操作:

    #alias BAR FOO  // nonexistent fantasy macro-cloning preprocessor directive
    

    也不是这样:

    #rename BAR FOO // like #alias BAR FOO followed by #undef FOO
    

    如果我们这样做:

    #define BAR FOO  // for the #define FOO 42 case
    

    这不是别名。定义宏BAR,使其替换标记序列是标记FOO,而不是42。如果FOO 宏消失,那么BAR 就失去了意义。

    另请注意,C 预处理器宏不能扩展为预处理指令,因此以下方法也不起作用

     // wrong:
     #define MACRO_DEFINER(NAME) \
       #define NAME 42
    
     MACRO_DEFINER(FOO) // hoping for #define FOO 42: no such luck
     MACRO_DEFINER(BAR) // hoping for #define BAR 42: likewise
    

    恐怕您必须后退几步才能找到替代策略来解决您要解决的任何问题。如果您遇到困难,请针对实际问题创建一个新问题。

    总是有代码生成:在构建时生成 C 或 C++。然后,只要您调整您的生成系统,您可以梦想的任何文本替换或扩展都是可能的。

    任何涉及#undef XYZ 的解决方案都有可能破坏库头的功能。图书馆可能会做这样的事情:

    #define XYZ 42 #define 宏(B) bloop(XYZ, B)

    如果我们使用macro,那么如果我们重新定义XYZ,就会破坏它。

    如果该库以定义XYZ 而闻名,并且我们设法在使用该库的代码中成功地重新定义了它,那么这种情况将会使未来的维护者感到困惑。 “哦,这个XYZ 实际上不是那个库;这个程序员只是想要一个不相关的XYZ。”

    这里最好的解决方案是停止使用XYZ 并找到其他名称。适应你正在使用的库;不要与他们发生冲突。

    【讨论】:

      【解决方案4】:

      使用另一个 .c 文件,并将宏值分配给全局变量。

      【讨论】:

        猜你喜欢
        • 2016-12-14
        • 2011-03-26
        • 2020-02-09
        • 2011-01-26
        • 1970-01-01
        • 2021-10-27
        • 2021-12-29
        • 2015-11-24
        • 1970-01-01
        相关资源
        最近更新 更多