逗号运算符的正确用法是什么?

Kam*_*Kam 37 c c++ coding-style comma-operator

我看到了这段代码:

if (cond) {
    perror("an error occurred"), exit(1);
}
Run Code Online (Sandbox Code Playgroud)

为什么要这么做?为什么不呢:

if (cond) {
    perror("an error occurred");
    exit(1);
}
Run Code Online (Sandbox Code Playgroud)

usr*_*301 54

在你的例子中,它完全没有任何理由.写作时,它有时很有用

if(cond)
  perror("an error occured"), exit(1) ;
Run Code Online (Sandbox Code Playgroud)

- 那你就不需要花括号了.但这是对灾难的邀请.

逗号运算符是将两个或多个表达式放在引用只允许一个的位置.在您的情况下,没有必要使用它; 在其他情况下,例如在while循环中,它可能是有用的:

while (a = b, c < d)
  ...
Run Code Online (Sandbox Code Playgroud)

其中while循环的实际"评估"仅受最后一个表达式的控制.

  • 换句话说,逗号运算符主要用于混淆. (36认同)
  • 逗号运算符组合了两个或多个*表达式*,而不是语句. (8认同)
  • @JamesKanze:或宏 - `#define show_error(str,code)perror(str),exit(code)`然后`show_error`表现为函数`if(cond)show_error("出错",1); .另见Grijesh Chauhan的回答. (2认同)

Bil*_*eal 19

逗号运算符的合法情况很少见,但确实存在.一个例子是当你想要在条件评估中发生某些事情时.例如:

std::wstring example;
auto it = example.begin();
while (it = std::find(it, example.end(), L'\\'), it != example.end())
{
    // Do something to each backslash in `example`
}
Run Code Online (Sandbox Code Playgroud)

它也可以用在你只能放置一个表达式的地方,但是想要发生两件事.例如,以下循环在for循环的第三个组件中递增x并递减y:

int x = 0;
int y = some_number;
for(; x < y; ++x, --y)
{
    // Do something which uses a converging x and y
}
Run Code Online (Sandbox Code Playgroud)

不要去寻找它的用途,但如果它是合适的,不要害怕使用它,如果你看到其他人使用它,不要被抛出一个循环.如果您有两件事没有理由不成为单独的语句,请将它们作为单独的语句而不是使用逗号运算符.

  • @BillyONeal 无论哪种方式,你都会在某种情况下产生副作用,这是应该避免的。这是一个很好的例子,说明逗号运算符可以更轻松地编写糟糕的代码。 (2认同)

Gri*_*han 6

通过一些例子可以更好地理解这一点:

首先: 考虑一个表达式:

   x = ++j;
Run Code Online (Sandbox Code Playgroud)

但暂时,如果我们需要分配一个临时调试值,那么我们可以这样写。

   x = DEBUG_VALUE, ++j; 
Run Code Online (Sandbox Code Playgroud)

第二:
逗号,运算符经常在for()循环中使用,例如:

for(i = 0, j = 10; i < N; j--, i++) 
 //      ^                   ^     here we can't use ;  
Run Code Online (Sandbox Code Playgroud)

第三:
再举一个例子(实际上人们可能会觉得这样做很有趣):

if (x = 16 / 4), if remainder is zero then print  x = x - 1;  
if (x = 16 / 5), if remainder is zero then print  x = x + 1;
Run Code Online (Sandbox Code Playgroud)

也可以一步完成;

  if(x = n / d, n % d) // == x = n / d; if(n % d)
    printf("Remainder not zero, x + 1 = %d", (x + 1));
  else
    printf("Remainder is zero,  x - 1 = %d", (x - 1));
Run Code Online (Sandbox Code Playgroud)

PS:也许有趣的是,有时使用 ,运算符是灾难性的。例如,在问题Strtok 用法,代码不工作,错误地,OP 忘记写函数的名称,而不是写tokens = strtok(NULL, ",'");,他写了,tokens = (NULL, ",'");并且他没有得到编译错误 - 但它是一个有效的表达式,tokens = ",'";导致无限循环他的节目。

  • 我认为你的第二个例子(`for`)占合法逗号运算符使用的 99%。 (2认同)

Pie*_*aud 5

逗号运算符允许在预期的地方对表达式进行分组。

例如,它在某些情况下很有用:

// In a loop
while ( a--, a < d ) ...
Run Code Online (Sandbox Code Playgroud)

但在你的情况下,没有理由使用它。会很混乱……就是这样……

在您的情况下,这只是为了避免使用花括号:

if(cond)
    perror("an error occurred"), exit(1);

// =>
if (cond)
{
    perror("an error occurred");
    exit(1);
}
Run Code Online (Sandbox Code Playgroud)

指向逗号运算符文档的链接。


Jam*_*nze 5

逗号运算符的主要用途是混淆;它允许在读者只期望一件的情况下做两件事情。最常见的用途之一 - 为条件添加副作用,属于这一类。但是,有几种情况可能被认为是有效的:

用于在 K&R 中表示它的那个:在for循环中递增两个变量。在现代代码中,这可能发生在类似std::transform, or的函数中std::copy,其中输出迭代器与输入迭代器同时递增。(当然,更多情况下,这些函数将包含一个while循环,在循环末尾的单独语句中递增。在这种情况下,使用逗号而不是两个语句是没有意义的。)

想到的另一种情况是初始化列表中输入参数的数据验证:

MyClass::MyClass( T const& param )
    : member( (validate( param ), param) )
{
}
Run Code Online (Sandbox Code Playgroud)

(这假设validate( param )如果出现错误,将抛出异常。)这种用法并不是特别有吸引力,尤其是因为它需要额外的括号,但没有太多替代方案。

最后,我有时会看到约定:

ScopedLock( myMutex ), protectedFunction();
Run Code Online (Sandbox Code Playgroud)

,这避免了必须为ScopedLock. 说实话,我不喜欢它,但我已经看到它被使用了,并且添加额外的大括号以确保ScopedLock立即销毁的替代方法也不是很漂亮。

  • “*逗号运算符的主要用途是混淆*”——我认为这不是真的。它当然*可以*以这种方式使用,但是有很多合法的非混淆用途。(如果您将观察限制在初学者编写的代码上,那么您可能是对的。) (6认同)