良好的详细宏 (C99)

发布于 2025-01-08 14:24:06 字数 519 浏览 6 评论 0原文

我正在写一个我想象的相当常见的宏。我想通过定义一组以下形式的宏来模拟许多 POSIX 程序上重复的“-v”选项:

#define V1(str, ...) if(optv >= 1){printf("%s: "str,prog,__VA_ARGS__);}

int main(int argc, char* argv[])
{
  // ... stuff ...
  int i = 1;
  V1("This contains a variable: %d\n",i);
}

// Output:
// ./program: This contains a variable: 1

其中 optv 计算在命令行上找到的“-v”选项的数量, prog 包含程序名称(均未显示)。这很有效,但问题是我必须使用变量。 V1("Output") 将生成编译器错误。我总是可以使用 V1("Output%s","") 但应该有一个更干净的解决方案。

I'm looking to write what I would imagine is a fairly common macro. I want to emulate the repeated "-v" options on many POSIX programs by defining a bunch of macros of the following form:

#define V1(str, ...) if(optv >= 1){printf("%s: "str,prog,__VA_ARGS__);}

int main(int argc, char* argv[])
{
  // ... stuff ...
  int i = 1;
  V1("This contains a variable: %d\n",i);
}

// Output:
// ./program: This contains a variable: 1

where optv counts the number of "-v" options found on the command line and prog contains the program name (neither shown). This works well, but the problem is that I have to use a variable. V1("Output") will generate a compiler error. I could always use V1("Output%s","") but there should be a cleaner solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

素年丶 2025-01-15 14:24:06

GNU C 预处理器有一个特殊功能,可以让您删除结尾的逗号当没有参数通过在 __VA_ARGS__ 前面添加标记粘贴运算符 ## 来填充可变参数部分时:

#define V1(str, ...) if(optv < 1); else printf("%s: "str,prog, ## __VA_ARGS__)

或者,如果您希望保留完全 C99兼容,您可以将格式字符串参数合并到省略号中,但在这种情况下,您还需要重构代码,因为您希望在格式字符串和可变参数之间包含额外的 prog 参数。像这样的东西可能会起作用:

#define V1(...) if(optv < 1); else myprintf(prog, __VA_ARGS__)
int myprintf(const char *prog, const char *fmt, ...)
{
    // Print out the program name, then forward the rest onto printf
    printf("%s: ", prog);

    va_list ap;
    va_start(ap, fmt);
    int ret = vprintf(fmt, ap);
    va_end(ap);

    return ret;
}

然后,V1("Output") 扩展为 myprintf(prog, "Output") 而不使用任何非 C99 编译器扩展。

编辑

另请注意,我反转了宏中的 if 条件,因为如果您在 if 内调用宏,可能会出现一些奇怪的问题不带大括号的声明 - 请参阅此常见问题解答以获得详细的解释。

The GNU C preprocessor has a special feature that lets you delete the trailing comma when there are no arguments filling the variadic portion by prepending the token-pasting operator ## to __VA_ARGS__:

#define V1(str, ...) if(optv < 1); else printf("%s: "str,prog, ## __VA_ARGS__)

Alternatively, if you wish to remain fully C99 compliant, you could incorporate the the format string parameter into the ellipsis, but in this instance you'll also need to refactor your code since you want to include the extra prog parameter between the format string and the varargs. Something like this might work:

#define V1(...) if(optv < 1); else myprintf(prog, __VA_ARGS__)
int myprintf(const char *prog, const char *fmt, ...)
{
    // Print out the program name, then forward the rest onto printf
    printf("%s: ", prog);

    va_list ap;
    va_start(ap, fmt);
    int ret = vprintf(fmt, ap);
    va_end(ap);

    return ret;
}

Then, V1("Output") expands to myprintf(prog, "Output") without using any non-C99 compiler extensions.

EDIT

Also note that I inverted the if condition in the macro, due to some weird issues that can arise if you invoke the macro inside an if statement without braces—see this FAQ for a detailed explanation.

动听の歌 2025-01-15 14:24:06

为什么不为每个详细级别使用 2 个不同的宏?一种打印消息和变量,另一种只打印消息?

Why don't you use 2 different macros for each verbosity level; one which prints a message and variable, and one which just prints a message?

过期以后 2025-01-15 14:24:06

您可能应该为自己编写一个小的支持函数,以便可以干净地完成工作:

extern void vb_print(const char *format, ...);

#define V1(...)  do { if (optv >= 1) vb_print(__VA_ARGS__); } while (0)

我假设 optvprog 都是全局变量。这些将进入标题(您不会将它们写在程序本身中,不是吗?)。

该功能可以是:

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

extern const char *prog;

void vb_print(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    printf("%s:", prog);
    vprintf(format, args);
    va_end(args);
}

其中没有火箭科学。您可以根据自己的喜好调整系统,允许选择信息的写入位置、刷新输出、确保末尾有换行符等。

You should probably write yourself a small support function so that you can do the job cleanly:

extern void vb_print(const char *format, ...);

#define V1(...)  do { if (optv >= 1) vb_print(__VA_ARGS__); } while (0)

I assume that both optv and prog are global variables. These would go into a header (you wouldn't write them out in the programs themselves, would you?).

The function can be:

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

extern const char *prog;

void vb_print(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    printf("%s:", prog);
    vprintf(format, args);
    va_end(args);
}

There's no rocket science in there. You can tweak the system to your heart's content, allowing a choice of where the information is written, flushing the output, ensuring there's a newline at the end, etc.

无尽的现实 2025-01-15 14:24:06

试试这个:

#define V1X(str, ...) if(optv >= 1) {printf("%s: "str,prog,__VA_ARGS__);} else
#define V1(...) V1X(__VA_ARGS__,0)

我相信这可以解决您所描述的问题,而最后的else解决了另一个问题。

Try this:

#define V1X(str, ...) if(optv >= 1) {printf("%s: "str,prog,__VA_ARGS__);} else
#define V1(...) V1X(__VA_ARGS__,0)

I believe that fixes the problem you described, and the else at the end fixed another problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文