我看到了这段代码:
if (cond) {
perror("an error occurred"), exit(1);
}
为什么要这么做?为什么不只是:
if (cond) {
perror("an error occurred");
exit(1);
}
我看到了这段代码:
if (cond) {
perror("an error occurred"), exit(1);
}
为什么要这么做?为什么不只是:
if (cond) {
perror("an error occurred");
exit(1);
}
在您的示例中,它根本没有任何理由。当写成时它有时很有用
if(cond)
perror("an error occured"), exit(1) ;
-- 那么你就不需要花括号了。但这是灾难的邀请。
逗号运算符是将两个或多个表达式放在引用只允许一个的位置。在您的情况下,无需使用它;在其他情况下,例如在 while 循环中,它可能很有用:
while (a = b, c < d)
...
其中 while 循环的实际“评估”仅由最后一个表达式控制。
逗号运算符的合法情况很少见,但确实存在。一个例子是当你想在条件评估中发生一些事情时。例如:
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`
}
它也可以用于只能放置一个表达式,但希望发生两件事的地方。例如,以下循环在 for 循环的第三个组件中递增 x 并递减 y:
int x = 0;
int y = some_number;
for(; x < y; ++x, --y)
{
// Do something which uses a converging x and y
}
不要去寻找它的用途,但如果合适的话,不要害怕使用它,如果你看到其他人在使用它,也不要陷入循环。如果您有两件事没有理由不成为单独的语句,请将它们分开,而不是使用逗号运算符。
举一些例子可以更好地理解这一点:
首先: 考虑一个表达式:
x = ++j;
但是暂时,如果我们需要分配一个临时的调试值,那么我们可以写。
x = DEBUG_VALUE, ++j;
第二:
逗号,
运算符经常在for()
-loop中使用,例如:
for(i = 0, j = 10; i < N; j--, i++)
// ^ ^ here we can't use ;
第三:
再举一个例子(实际上可能会觉得这样做很有趣):
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;
也可以一步完成;
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));
PS:知道有时使用 ,
运算符是灾难性的也可能很有趣。例如,在问题Strtok usage, code not working中,错误地,OP 忘记写函数的名称,而不是写tokens = strtok(NULL, ",'");
,他写了tokens = (NULL, ",'");
,他没有得到编译错误——但它是一个有效的表达式,tokens = ",'";
导致无限循环他的节目。
逗号运算符允许将表达式分组到预期的位置。
例如,它在某些情况下很有用:
// In a loop
while ( a--, a < d ) ...
但在你的情况下,没有理由使用它。会很混乱……就是这样……
在你的情况下,这只是为了避免花括号:
if(cond)
perror("an error occurred"), exit(1);
// =>
if (cond)
{
perror("an error occurred");
exit(1);
}
逗号运算符文档的链接。
逗号运算符的主要用途是混淆;它允许做两件读者只期望一件的事情。最常见的用途之一——给病情增加副作用,属于这一类。然而,有一些情况可能被认为是有效的:
用于在 K&R 中呈现它的一个:在for
循环中增加两个变量。在现代代码中,这可能发生在类似std::transform
或的函数中std::copy
,其中输出迭代器与输入迭代器同时递增。(当然,更常见的情况是,这些函数将包含一个while
循环,在循环结束时在单独的语句中递增。在这种情况下,使用逗号而不是两个语句是没有意义的。)
另一个想到的情况是初始化列表中输入参数的数据验证:
MyClass::MyClass( T const& param )
: member( (validate( param ), param) )
{
}
(这假设如果validate( param )
出现问题会抛出异常。)这种用法并不是特别有吸引力,特别是因为它需要额外的括号,但没有很多替代方案。
最后,我有时会看到约定:
ScopedLock( myMutex ), protectedFunction();
,这避免了必须为ScopedLock
. 说实话,我不喜欢它,但我已经看到它使用过,并且添加额外的大括号以确保ScopedLock
立即破坏的替代方法也不是很漂亮。
运算符 () 的实际用途似乎很少。
Bjarne Stroustrup,C++ 的设计与演进
大多数常用的逗号可以在维基百科文章Comma_operator#Uses中找到。
我在使用boost::assign时发现了一个有趣的用法,它明智地重载了运算符,使其表现为逗号分隔的值列表,可以推到向量对象的末尾
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope
{
vector<int> values;
values += 1,2,3,4,5,6,7,8,9; // insert values at the end of the container
}
不幸的是,一旦编译器开始支持统一初始化,上述在原型设计中流行的用法现在看起来已经过时了
所以这让我们回到
运算符 () 的实际用途似乎很少。
Bjarne Stroustrup,C++ 的设计与演进
在您的情况下,逗号运算符是无用的,因为它可以用来避免花括号,但事实并非如此,因为作者已经放了它们。因此它是无用的,可能会令人困惑。
如果您想在条件为true或false时执行两个或多个指令,它可能对行程运算符很有用。但请记住,由于逗号运算符从左到右评估规则,返回值将是最右边的表达式(我的意思是在括号内)
例如:
a<b?(x=5,b=6,d=i):exit(1);
boost::assign
重载逗号运算符以实现这种语法:
vector<int> v;
v += 1,2,3,4,5,6,7,8,9;