如何重命名 C 预处理器宏?
How to rename a C preprocessor macro?
考虑一个 (read-only third-party) header 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
扩展到它的最终值?
使用另一个 .c 文件,并将宏值分配给全局变量。
pre-processor 没有,至少,据我所知没有。
但是,对于您的示例中已知类型的简单常量,有一个解决方法。
#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
的绒毛,此代码为pre-processed以下
enum xyz_constants
{
LIB_XYZ = 42,
};
int
main()
{
printf("old value: %d, new value: %d\n", LIB_XYZ, 27);
return 0;
}
您可以在某种程度上将其扩展到其他数据类型和某些 function-like 宏,但当然有限制。
无论如何,为什么需要特定标识符 XYZ
?不能为您的宏使用不同的名称吗?
如果 lib.h
中的 XYZ
是一个 数字 [或各种常量],您可以使用 enum
:
enum { LIB_XYZ = XYZ };
#undef XYZ
如果 XYZ
是 不是 以上,您必须创建(例如)myxyz.c
是 不是 包括 lib.h
并在那里使用 XYZ
(其他文件可能包括 xyz.h
)
不同之处在于,#define LIB_XYZ XYZ
不会在那一行解析,只有当你以后使用它时才会解析,如:
foo(LIB_XYZ);
所以这行不通,因为您已经 #undef'ed
XYZ
。
预处理器符号是一个名称。没有在保留内容的同时更改名称本身的预处理指令。例如,给定:
#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
而为人所知,并且我们设法在使用该库的代码中成功地重新定义了它,这种情况会让未来的维护者感到困惑。 "Oh, this XYZ
is not actually that library one; this programmer just wanted an unrelated XYZ
."
这里最好的解决办法是停止使用 XYZ
并找到其他名称。适应您正在使用的库;不要和他们发生冲突。
考虑一个 (read-only third-party) header 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
扩展到它的最终值?
使用另一个 .c 文件,并将宏值分配给全局变量。
pre-processor 没有,至少,据我所知没有。
但是,对于您的示例中已知类型的简单常量,有一个解决方法。
#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
的绒毛,此代码为pre-processed以下
enum xyz_constants
{
LIB_XYZ = 42,
};
int
main()
{
printf("old value: %d, new value: %d\n", LIB_XYZ, 27);
return 0;
}
您可以在某种程度上将其扩展到其他数据类型和某些 function-like 宏,但当然有限制。
无论如何,为什么需要特定标识符 XYZ
?不能为您的宏使用不同的名称吗?
如果 lib.h
中的 XYZ
是一个 数字 [或各种常量],您可以使用 enum
:
enum { LIB_XYZ = XYZ };
#undef XYZ
如果 XYZ
是 不是 以上,您必须创建(例如)myxyz.c
是 不是 包括 lib.h
并在那里使用 XYZ
(其他文件可能包括 xyz.h
)
不同之处在于,#define LIB_XYZ XYZ
不会在那一行解析,只有当你以后使用它时才会解析,如:
foo(LIB_XYZ);
所以这行不通,因为您已经 #undef'ed
XYZ
。
预处理器符号是一个名称。没有在保留内容的同时更改名称本身的预处理指令。例如,给定:
#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
而为人所知,并且我们设法在使用该库的代码中成功地重新定义了它,这种情况会让未来的维护者感到困惑。 "Oh, this XYZ
is not actually that library one; this programmer just wanted an unrelated XYZ
."
这里最好的解决办法是停止使用 XYZ
并找到其他名称。适应您正在使用的库;不要和他们发生冲突。