简体   繁体   English

如何在C中使用可变参数宏修复“左手操作数无效”警告

[英]How to fix `left hand operand has no effect` warning with variadic macro in C

I'm using the variadic macro to simulate a default argument.我正在使用可变参数宏来模拟默认参数。 I compile with -Wunused-value .我用-Wunused-value编译。 Thus, I get the following warning:因此,我收到以下警告:

warning: left-hand operand of comma expression has no effect

Is there a way to somehow fix this warning without having to remove -Wunused-value ?有没有办法以某种方式修复此警告而不必删除-Wunused-value or do I have to end up using #pragma GCC diagnostic ignored "-Wunused-value" ?还是我必须最终使用#pragma GCC diagnostic ignored "-Wunused-value"

#include <stdio.h>

#define SUM(a,...) sum( a, (5, ##__VA_ARGS__) )

int sum (int a, int b)
{
  return a + b;
}

int main()
{
  printf("%d\n", SUM( 3, 7 ) );
  printf("%d\n", SUM( 3 ) );
}

The ## construct that you are using is a gcc speciality and not portable.您使用的##构造是 gcc 的专长,不可移植。 Don't use it, there are other ways.不要用它,还有其他方法。

The following should do what you expect以下应该做你期望的

#define SUM2(A, B, ...) sum((A), (B))
#define SUM1(...) SUM2(__VA_ARGS__)
#define SUM(...) SUM1(__VA_ARGS__, 5, 0)

Such games with macro default arguments are frowned upon by many, because they may make the code more difficult to read.许多人不喜欢这种带有宏默认参数的游戏,因为它们可能会使代码更难阅读。 For the moment I'd suggest that you don't use such constructs in your programs.目前我建议你不要在你的程序中使用这样的结构。 You should perhaps learn more of the basics before you go into such esoteric stuff.在你进入这些深奥的东西之前,你或许应该学习更多的基础知识。

Also your idea to want to silence the compiler is really a bad one.此外,您想让编译器静音的想法确实很糟糕。 The compiler is there to help you, listen to him.编译器会帮助你,听他的。 In the contrary, raise the warning level to a maximum and improve your code until it compiles without any warning.相反,将警告级别提高到最大并改进您的代码,直到它在没有任何警告的情况下编译。

Jens Gustedt proposed a very good problem-specific portable solution. Jens Gustedt 提出了一个非常好的针对特定问题的便携式解决方案。 I didn't know, ,##__VA_ARGS__ is a GCC extension (maybe Clang too?).我不知道, ,##__VA_ARGS__是 GCC 扩展(也许 Clang 也是?)。 There are however GCC-specific solutions for the authors initial intension.然而,对于作者的初始意图,有 GCC 特定的解决方案。

As a problem-specific and very GCC-specific solution, you can use _Pragma("GCC diagnostic ignored \\"-Wunused-value\\"") and delimit it around the macro expansion.作为特定于问题且非常特定于 GCC 的解决方案,您可以使用_Pragma("GCC diagnostic ignored \\"-Wunused-value\\"")并在宏扩展周围对其进行分隔。 This will keep the comfort of readability.这将保持可读性的舒适度。 This does not work everywhere.这并不适用于所有地方。 It mainly fails within static initializer lists placed outside of functions where those pragmas can't be applied.它主要在无法应用这些编译指示的函数之外的静态初始值设定项列表中失败。 I really was looking for a solution within such initializer lists because I couldn't find any which hides the warning pragmas from the reader.我真的在这样的初始化列表中寻找解决方案,因为我找不到任何隐藏警告编译指示的内容。 Other than that, for a function call like sum() for example - which I suppose to be only valid in a function body itself -, you can use it:除此之外,对于像sum()这样的函数调用——我认为它只在函数体本身中有效——你可以使用它:

#define SUM(a,...) ({\
    _Pragma("GCC diagnostic push")\
    _Pragma("GCC diagnostic ignored \"-Wunused-value\"")\
    sum( a, (5, ##__VA_ARGS__) );\
    _Pragma("GCC diagnostic pop")\
})

Remember, you can only use it in function bodies and where an expression is expected.请记住,您只能在函数体和需要表达式的地方使用它。 The warning will remain turned on after the macro expansion.宏扩展后警告将保持打开状态。

But I found a general solution!但我找到了一个通用的解决方案! Conditional-macro-expansion is possible with the ,##__VA_ARGS__ feature.使用,##__VA_ARGS__功能可以进行条件宏扩展。 It gives you the power of conditional expansion based on blankness of the argument.它为您提供了基于论证空白的条件扩展的力量。

This feature does not necessarily add substitution power to the preprocessor.此功能不一定会为预处理器增加替代能力。 If you use arguments which include commas like (<...>) for false or 0 and (<...>,<...>) for true or 1, you can achieve the same.如果您使用包含逗号的参数,例如(<...>)表示假或 0 和(<...>,<...>)表示真或 1,则可以实现相同的效果。 But only the conditional comma allows you the comfort of expanding conditionally based on the blankness of an argument.但是只有条件逗号允许您根据参数的空白进行有条件的扩展。

See: you might be able to write your code like SUM(A) expanding to sum((A),5) without ##__VA_ARGS__ but you might not be able to write SUM(,B) expanding to sum((somevalue),B) .请参阅:您可能可以编写像SUM(A)扩展为sum((A),5)而无需##__VA_ARGS__但您可能无法编写SUM(,B)扩展为sum((somevalue),B) But you can do that with ##__VA_ARGS__ .但是你可以用##__VA_ARGS__做到这##__VA_ARGS__

Example:例子:

#define _VADIC(...) , ##__VA_ARGS__

//expands to A if A is not blank else to __VA_ARGS__ as fallback value
#define TRY(A,B) _TRY0(_VADIC(A), B)
#define _TRY0(...) _TRY1(__VA_ARGS__) /*expand before call*/
#define _TRY1(A, B, ...) B

//expands to THEN if A is blank otherwise expands to blank
#define IF(A,THEN) _IF0(_VADIC(A),THEN)
#define _IF0(...) _IF1(__VA_ARGS__) /*expand before call*/
#define _IF1(A,B,...) __VA_ARGS__

//expands to ELSE if A is not blank otherwise expands to blank
#define IFNOT(A,ELSE) _IFNOT0(_VADIC(A),,ELSE)
#define _IFNOT0(...) _IFNOT1(__VA_ARGS__) /*expand before call*/
#define _IFNOT1(A,B,C,...) C

#define IF_ELSE(A, THEN, ELSE) IF(A,THEN)IFNOT(A,ELSE)

Without the conditional comma, you only can expand conditionally on the number of arguments or on predefined concatenations but this way, you can use ANY single undefined symbol as condition.如果没有条件逗号,您只能根据参数数量或预定义的连接有条件地扩展,但是这样,您可以使用任何单个未定义符号作为条件。

PS: What about loops? PS:循环呢? Macros in C are designed to be finite for faster compilation. C 中的宏被设计为有限的以加快编译速度。 You won't get infinite loops since the limit of loop cycles depends on the source code size.您不会得到无限循环,因为循环周期的限制取决于源代码大小。 Limited loops is the only thing which hinders you from turing-completeness, but practical real-world computer science problems (different from embedded or operating systems) don't need infinite loops for calculations.有限循环是唯一阻碍您实现图灵完整性的东西,但实际的现实世界计算机科学问题(不同于嵌入式或操作系统)不需要无限循环进行计算。 They are all limited depending with the problem size.它们都受到限制,具体取决于问题的大小。 The turing machine also uses a finite alphabet of symbols.图灵机还使用有限的符号字母表。 You could know the limit of loop cycles which are needed in the worst case and it is possible to create a functional loop (a "reduce" or "filter" macro) running on variable-length macro argument lists which can reformat the macro argument list and do magic.您可以知道在最坏情况下所需的循环周期的限制,并且可以创建一个在可变长度宏参数列表上运行的功能循环(“reduce”或“filter”宏),它可以重新格式化宏参数列表并做魔术。 The only requirement is the comma.唯一的要求是逗号。 You can't iterate over elements without a comma in between.您不能在元素之间没有逗号的情况下迭代元素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM