gpt4 book ai didi

c - 如果缺少参数,则将宏扩展为不同的默认宏

转载 作者:行者123 更新时间:2023-12-02 08:31:50 24 4
gpt4 key购买 nike

如果第一个参数不是预期值,是否可以将一个接受多个参数的宏扩展到另一个宏

例如

int main()
{
PRINT(2, "%d%d\n", i, j); //should expand to syslog(2, "%d%d\n", i, j)
PRINT("%d%d\n", i, j); //arg1 which is expected to be an int is not preset.
/* This should expand differently may be to a default level say 3. syslog(3, "%d%d\n", i,j); */
}

我会尝试 this如果我知道 args 的总数,那就有点过载了。

最佳答案

我真的建议为此编写两个单独的宏,就像您为 C 中的两个签名编写两个不同名称的函数一样。(我宁愿编写宏来明确地告诉您它们是什么级别,例如 ERROR (...)WARNING(..) 等而不是引入默认参数。)

也就是说,有两种可能性可以实现您想要的。

C11 _Generic 选择

_Generic 关键字是在 C11 中引入的。它允许根据参数的类型以类似于 switch 的方式扩展宏; Robert Gamble 有一个 good introduction .

您想区分两种情况:第一个参数是字符串,第一个参数是整数。缺点是在 _Generic 中,字符串文字不被视为 char *const char *,而是被视为 char[尺寸]。例如,"%d" 是一个 char[3]

在您的情况下,我们可以通过将字符串视为任何非整数来解决此问题。编译器稍后会整理出所有非字符串、非整数参数。所以:

#define PRINT(fmt, ...)                              \
_Generic(fmt, \
int: syslog(fmt, __VA_ARGS__), \
default: syslog(3, fmt, __VA_ARGS__))

缺点是:您不能进行单参数调用,因为那样会在调用中留下一个逗号。 (gcc 的 ##__VA_ARGS__ 解决了这个问题。)而且 _Generic 关键字还没有广泛实现;此解决方案将使您的代码非常不可移植。

字符串自省(introspection)技巧

普通的 C99 宏没有关于它们类型的信息。但是,C 代码可以进行猜测。下面是一个检查宏参数是否为字符串文字的示例:

#define PRINT(sev, ...)                            \
if (#sev[0] == '"') syslog(3, sev, __VA_ARGS); \
else syslog(sev, __VA_ARGS__);

这几乎行得通。编译器可能会将常量条件编译掉,只为其中一个分支生成代码。但无论如何它都会解析分支,死分支将有一个错误的函数签名,这将产生警告。

您可以通过在 C 中编写可变参数前端函数来解决这个问题。这是一个有效的示例:

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

#define HEAD(X, ...) X
#define STR_(x) #x
#define STR(x) STR_(x)

#define PRINT(...) \
msg(*STR(HEAD(__VA_ARGS__)) == '"', __VA_ARGS__)

int msg(int dflt, ...)
{
va_list va;
int sev = 3;
const char *fmt;

va_start(va, dflt);
if (!dflt) sev = va_arg(va, int);
fmt = va_arg(va, const char *);

fprintf(stderr, "[%d] ", sev);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");

va_end(va);

return 0;
}

int main()
{
PRINT(1, "Incompatible types %s and %s", "Apple", "Orange");
PRINT("Microphone test: %d, %d, %d, ...", 1, 2, 3);

return 0;
}

这个解决方案很危险,因为 msg 函数只有在由宏生成时才是安全的。只有当格式字符串是以双引号开头的字符串文字时,宏才是安全的。该宏将参数向左扩展一个 bool 参数,并将参数不兼容隐藏在可变参数列表中。

这可能是个不错的技巧,但最好使用单独的、命名清晰的宏。

关于c - 如果缺少参数,则将宏扩展为不同的默认宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25848461/

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