我已经注意到,在重构 C 和 C + + 代码的各个部分时,使用逗号而不是分号来分隔语句。就像这样
int a = 0, b = 0; a = 5, b = 5;
在我期待的地方
int a = 0, b = 0; a = 5; b = 5;
我知道 C 和 C + + 允许使用逗号来分隔语句(特别是循环头) ,但是这两段代码之间有什么区别呢?我猜测逗号是剪切和粘贴的结果,但它是一个 bug 吗? 它会影响执行吗?
逗号是一个运算符,它返回的值总是第二个(右)参数,而分号只是结束语句。这允许在其他语句中使用逗号运算符,或者将多个语句连接为一个语句。
这里调用函数 f (x) ,然后为 if 语句计算 x > y。
x > y
if( y = f(x), x > y )
一个例子,当它只是用来避免一个块的需要
if( ... ) x = 2, y = 3; if( ... ) { x = 2; y = 3; }
这对你发布的代码没有影响。一般来说,逗号分隔表达式就像分号一样,但是,如果将整体作为表达式,那么逗号运算符意味着表达式的计算结果为最后一个参数。
这里有一个例子:
b = (3, 5);
将计算3,然后5,并将后者赋值给 b。因此 b = 5。注意括号在这里很重要:
b = 5
b = 3, 5;
将计算 b = 3,然后是5,整个表达式的结果是5,但是 b == 3。
b = 3
b == 3
当迭代器代码不是简单的 i++,但需要执行多个命令时,逗号操作符在 for-loop 中特别有用。在这种情况下,分号不能很好地与 for 循环语法一起工作。
i++
一种用法是代码高尔夫:
if (x == 1) y = 2, z = 3; if (x == 1) { y = 2; z = 3; }
第一行比较短,但是在常规开发中看起来太混乱了。
逗号运算符从左到右计算所有操作数,结果是最后一个操作数的值。
如果您希望在“增量”部分执行多个操作,例如(逆转字符串) ,那么在 for 循环中它最为有用
for (int lower = 0, upper = s.size() - 1; lower < upper; ++lower, --upper) std::swap(s[lower], s[upper]);
另一个例子,它可能是一个选项(查找字符串中的所有匹配项) :
#include <string> #include <iostream> int main() { std::string s("abracadabra"); size_t search_position = 0; size_t position = 0; while (position = s.find('a', search_position), position != std::string::npos) { std::cout << position << '\n'; search_position = position + 1; } }
特别是,逻辑 还有不能用于此条件,因为零和非零都可能意味着字符在字符串中找到。另一方面,使用逗号时,每次计算条件时都会调用 position = s.find(),但是这部分条件的结果被忽略。
position = s.find()
当然,还有其他写循环的方法:
while ((position = s.find('a', search_position)) != std::string::npos)
或者只是
while (true) { position = s.find('a', search_position); if (position == std::string::npos) break; ... }
作为 弗兰克提到过,在示例中如何使用逗号运算符并不会导致 bug。逗号运算符可能会混淆,原因有以下几点:
由于逗号操作符容易混淆,而且常常是不必要的,因此除了一些非常特殊的情况外,应该避免使用逗号操作符:
for
根据定义,逗号操作符是一个 hackish 操作符——它是指在只允许一个操作符的情况下对两个事物进行黑客操作。几乎总是丑陋的,但有时这就是你的全部。这是你唯一应该使用它的时候-如果你有其他选择,不要使用逗号运算符。
我想不出还有什么其他理由使用这个操作符,因为在大多数其他情况下,你可以通过在单独的语句中计算表达式来获得类似的效果(尽管我确信有人会对我忽略的另一个用法进行评论)。