如果缺少参数,则将宏扩展为其他默认宏 [英] Expanding a macro to a different default macro if an argument is missing

查看:84
本文介绍了如果缺少参数,则将宏扩展为其他默认宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to expand a macro which accepts multiple arguments to a different macro if first argument is not the expected value

Eg

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); */
}

我会尝试如果我知道args的总数,则这种过载。

推荐答案

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

I really recommend to write two separate macros for this, just as you would write two differently named functions for the two signatues in C. (I would rather write macros that tell you what level they are explicitly, like ERROR(...), WARNING(..) etc. than introduce a default argument.)

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

That said, there are two possibilities to achieve what you want.

C11引入了 _Generic 关键字。它允许根据参数的类型以类似于 switch 的方式扩展宏。罗伯特·格兰伯(Robert Gamble)具有很好的介绍

The _Generic keyword was introduced with C11. It allows to expand macros in a switch-like manner according to the type of an argument; Robert Gamble has a good introduction.

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

You want to distinguish two cases: First argument is a string and first argument is an integer. A drawback is that in _Generic, a string literal isn't treated as char * or const char *, but as char[size]. For example, "%d" is a char[3].

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

In your case, we can get around this by treating a string as anything that isn't an integer. The compiler will sort out all non-string, non-integer arguments later. So:

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

有缺点:您不能进行单参数调用,因为那样会在调用中留下逗号。 (gcc的 ## __ VA_ARGS __ 解决了这个问题。) _Generic 关键字尚未广泛实施;

There are drawbacks: You can't have a single-argument call, because that would leave a comma in the call. (gcc's ##__VA_ARGS__ gets around that.) And the _Generic keyword is not yet widely implemented; this solution will make your code highly unportable.

普通的C99宏在其上没有任何信息类型。但是,C代码可以猜测。这是一个检查宏参数是否为字符串文字的示例:

Ordinary C99 macros have no information on their type. C code can make a guess, however. Here's an example that checks whether a macro argument is a string literal:

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

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

This works -- almost. The compiler will probably compile the constant condition away and only gererate code for one of the branches. But it will parse the branches anyway and the dead branch will have a wrong function signature, which will generate warnings.

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

You can get around this by writing a variadic front-end function in C. Here's an example that works:

#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 函数仅在由宏生成时才安全。并且仅当格式字符串是以双引号开头的字符串文字时,宏才是安全的。宏通过一个布尔型参数向左扩展参数,并将参数不兼容隐藏在可变参数列表中。

This solution is dangerous, because the msg function is only safe if it is generated by the macro. And the macro is only safe if the format string is a string literal beginning with a double quote. The macro expands the arguments by one boolean argument to the left and hides the argument incompatibility in a variadic argument list.

这可能是一个不错的技巧,但您会最好有单独的,命名明确的宏。

It may be a nice trick, but you'll be better off having separate, clearly named macros.

这篇关于如果缺少参数,则将宏扩展为其他默认宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆