这个__VA_ARGS__扩展是否有效c99?

时间:2018-06-18 18:35:30

标签: c c-preprocessor variadic-functions variadic-macros

我正在尝试编写一个采用可变参数的函数。它有以下原型:

void foo(const char *name, const char *file, uint32_t line, const char *fmt, ...);

我用以下宏调用它:

#define FOO(name, ...) \
    foo(name, __FILE__, __LINE__, __VA_ARGS__);

据我了解,以下内容有效:

FOO("Example, "Hello %s", "Stack Overflow");

但是,在符合标准的c99编译器中,以下结果会导致未定义的行为吗?

FOO("Example", "Hello Stack Overflow");

我担心的是,因为foo期望*fmt以及...只有两个参数传递给,时才会添加std=c99。宏。

有人能告诉我上述是否有效c99?

编辑:当我使用gcc和var arr = [[0,1],[0,2],[1,1],[1,1],[2,2],[2,2],[2,4],[5,6]] // var filtered = [[0,2],[1,1],[2,4]] // temp array to store key value pairs var items = [] arr.map((item) => { let [x, y] = item // store the max value of y for this x in items if (typeof items[x] === 'undefined'){ items[x] = y }else{ items[x] = Math.max(items[x], y) } }) var filtered = items.map((y, x) => { // rejoin data into x,y pairs return [x,y] }).filter(a => !!a) // fitler undefined pairs console.log(filtered)运行时,它有效,但我担心有无声的UB

谢谢!

2 个答案:

答案 0 :(得分:2)

作为也与可变参数有关的辅助节点,C要求必须为的可变参数部分提供至少一个参数(在原始问题中就是这种情况)。

来自ISO / IEC 9899:TC2§6.10.3:4:

  

如果宏定义中的标识符列表没有以。结尾   省略号,参数的数量(包括那些参数   在调用a时不包含预处理标记   类函数宏应等于宏中的参数个数   定义。否则,调用中应该有个更多的参数   比宏定义中的参数(不包括......)

还有一个草案解决了这个问题:http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2034.htm

幸运的是,大多数现代编译器要么抑制尾随逗号,要么提供某种解决方法。但是,这是编译器特定的行为。

在原始帖子中,FOO宏的可变部分被赋予字符串文字"Hello Stack Overflow"。扩展宏后,可以按如下方式调用foo函数:

foo("Example", "someFile.c", 42 "Hello Stack Overflow");

这很好,只要foo函数通过某种方式意识到在最后一个固定参数之后没有更多的参数可以预期。

答案 1 :(得分:2)

C标准的6.10.3.1 Argument substitution, paragraph 2

  

替换列表中出现的标识符__VA_ARGS__应该   被视为是一个参数,变量参数应该被视为   形成用于替换它的预处理令牌

因此,__VA_ARGS__将替换为作为宏的参数传递的所有标记。

所以,在你的情况下,给定宏:

#define FOO(name, ...) \
    foo(name, __FILE__, __LINE__, __VA_ARGS__);

调用
FOO("Example", "Hello Stack Overflow");

和函数声明

void foo(const char *name, const char *file, uint32_t line, const char *fmt, ...);

会产生类似

的结果
 foo( "Example", "asdf.c", 1234, "Hello Stack Overflow" );

并且在foo的调用中没有未定义的行为。 (foo()内部发生的事情可能仍然是UB。)