gpt4 book ai didi

c - 奇怪的宏扩展

转载 作者:太空宇宙 更新时间:2023-11-04 08:04:34 25 4
gpt4 key购买 nike

我想在c中模拟类,并用宏隐藏实现,但我得到了意外的宏扩展行为。

#define decl_class struct class { void *base ## ;
#define end_class } ## ; typedef struct class class ## ;
#define decl_methods struct class ## Methods {
#define method(returnType, methodName, ...) returnType (*methodName)(struct class *self, __VA_ARGS__) ## ;
#define end_methods } ## ;


#define class Integer
decl_class

int value;

decl_methods
method(int, getValue)
end_methods

end_class

#undef class


#define class Double
decl_class

double value;

decl_methods
method(double, getValue)
end_methods

end_class

#undef class

编译器说我声明了两次 struct classMethods(class 应该是类的名称)。这意味着“类”不会在我想要的时候被替换。甚至可以这样做吗?

最佳答案

你的第一个问题是

#define end_methods } ## ;

是语法错误(如果扩展了宏),因为标记粘贴的结果不是单个 有效标记。你应该得到像

这样的错误信息
error: pasting "}" and ";" does not give a valid preprocessing token

您的第二个问题是标记粘贴在嵌套宏展开之前执行。这意味着你的宏

#define decl_methods struct class ## Methods {

实际上和你写的一样

#define decl_methods struct classMethods {

让它做你想做的事,class必须是类函数宏的形式参数:

#define decl_class(class)   struct class {
#define end_class(class) }; typedef struct class class;
#define decl_methods(class) struct class ## Methods {
#define end_methods(class) };
#define method(class, returnType, methodName, ...) \
returnType (*methodName)(struct class *self, __VA_ARGS__);

然后

decl_class(Double)
double value;
decl_methods(Double)
method(Double, double, get_value);
end_methods(Double)
end_class(Double)

我想你可以避免在每个宏调用中重复类的名称,方法是使用一组附加的宏来粘贴 class伪参数,但是(由于太乏味的原因无法进入这里;阅读 Argument Prescan 的“GNU CPP manual”部分非常仔细)你将需要两个 层层嵌套展开以获得你想要的效果:

#define decl_class__(class_)   struct class_ {
#define decl_class_(class_) decl_class__(class_)
#define decl_class decl_class_(class)

#define decl_methods__(class_) struct class_ ## Methods {
#define decl_methods_(class_) decl_methods__(class_)
#define decl_methods decl_methods_(class)

/* etc */

这在技术上仅在最内层的宏需要使用 ## 时才需要(或 # )但是如果你真的打算在一个真正的程序中使用这些宏,你应该对所有这些宏统一使用,否则六个月后你就会精疲力竭。

在你完成所有那个之后,你会发现你的method宏不适用于零参数方法,例如

#define class Integer
method(int, getValue)

要么抛出错误,因为在标准 C 中,...在宏参数列表中必须接收至少一个参数,否则它会扩展为语法无效的声明,

int (*getValue)(struct Integer *self, );

解决这个问题的唯一方法是使用 GNU 扩展:

#define method__(class_, returnType, methodName, ...) \
returnType (*methodName)(struct class_ *self, ##__VA_ARGS__);

在 GNU 扩展 C 中,##,之间和 __VA_ARGS__具有在 ... 时导致逗号被删除的特殊效果没有收到任何争论。 (这个扩展是在大约 15 年前提出的标准化,但委员会不感兴趣。)

在这一点上,我邀请您重新考虑仅使用 C++ 的可能性。

关于c - 奇怪的宏扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43738294/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com