通过宏实现函数是布尔的噩梦。我已经为(通用)函数的头部和主体定义了宏。使用布尔型时,结果很奇怪。
我知道,这通常是出于可维护性而要避免的东西〜但就我而言,它是一组非常相似的回调函数和一个非常苛刻的缩写。
因此,目标实际上是可维护性和可读性,尤其是代码一致性。
#include <stdio.h>
#include <stdbool.h>
#define FUN_H(TYPE) \
void fun_##TYPE( void )
#define FUN(TYPE) \
FUN_H(TYPE) { \
printf("Type is " #TYPE ".\n"); \
}
FUN_H(int);
FUN_H(bool);
FUN(int);
FUN(bool);
int main(void) {
fun_int();
fun_bool();
}
阅读代码,我希望输出“ Type is int”。和“类型是布尔”。
实际上,要使代码编译(当前gcc / clang),必须将最后一次调用更改为fun__Bool();
,并将标头更改为FUN_H(_Bool);
-如果您知道C99,但实际上会有意义,但是会生成不连贯的代码。
_Bool
类型FUN_H(_Bool);
FUN(_Bool); // or FUN(bool);
int main(void) {
fun__Bool();
}
FUN()
宏#define FUN(TYPE) \
void fun_##TYPE( void ) { \
printf("Type is " #TYPE ".\n"); \
}
typedef
for _Bool
typedef _Bool mybool;
FUN_H(mybool);
FUN(mybool);
int main(void) {
fun_mybool();
}
bool
更改为typedef
#undef bool
typedef _Bool bool;
FUN_H(bool);
FUN(bool);
int main(void) {
fun_bool();
}
那我应该做什么?
答案 0 :(得分:5)
如果FUN_H
是宏,则内部bool
宏调用将_Bool
扩展为bool
。如果您丢失了内部FUN_H
宏并直接像这样写FUN
:
#include <stdio.h>
#include <stdbool.h>
#define FUN_H(TYPE) \
void fun_##TYPE( void )
#define FUN(TYPE) \
void fun_##TYPE( void ) { \
printf("Type is " #TYPE ".\n"); \
}
FUN_H(int);
FUN_H(bool);
FUN(int);
FUN(bool);
int main(void) {
fun_int();
fun_bool();
}
那么,即使fun_bool
是一个宏,您也会得到预期的bool
。
答案 1 :(得分:3)
如前所述,将TYPE
传递到任何中间宏将强制其扩展,然后再进行进一步处理。因此,串联必须尽早进行,然后再将TYPE
传递到任何地方。要实现此目标而又无需过多重复,我们可以将其委托给第三个宏
#define FUN_H(TYPE) \
FUN_H_(fun_##TYPE)
#define FUN_H_(NAME) \
void NAME( void )
#define FUN(TYPE) \
FUN_H_(fun_##TYPE) { \
printf("Type is " #TYPE ".\n"); \
}
答案 2 :(得分:1)
无论如何,您需要处理的动态是预处理器通过一系列(重新)扫描/全扩展操作来操作。出现在宏 M 扩展中的宏名称本身仅在重新扫描 M 的完整扩展(包括其所有参数和/或扩展名)的情况下扩展。令牌粘贴和字符串化的应用程序。
因此,如果宏参数是类似对象的宏的名称,则不能将其作为另一个宏的参数本身进行传递-如果您尝试这样做,则将传递该宏的扩展。这里的问题通常是如何确保在字符串化或粘贴令牌时发生这种情况,因此您想解决的问题有点不寻常。
您已经提出了许多您似乎不满意的替代方法,但这是一种具有您到目前为止讨论的所有优点,而又没有缺点的方法:定义一个额外的宏来修补不需要的宏扩张。例如,
#include <stdio.h>
#include <stdbool.h>
// This macro corrects the unwanted expansion to the wanted one:
#define fun__Bool fun_bool
// The rest of the code is identical to your initial, non-working example
#define FUN_H(TYPE) \
void fun_##TYPE( void )
#define FUN(TYPE) \
FUN_H(TYPE) { \
printf("Type is " #TYPE ".\n"); \
}
FUN_H(int);
FUN_H(bool);
FUN(int);
FUN(bool);
int main(void) {
fun_int();
fun_bool();
}
或者,您可以改为引入一个宏,该宏以相反的方式交换函数标识符,从而使调用得到更改,而不是声明。
我认为还有其他选择可以让您使用示例的原始样式,但是到目前为止,我已经考虑过的所有此类方法都更加混乱且脆弱。