在while循环条件下分配值
我在维基百科上找到了这段代码。
#include int main(void) { int c; while (c = getchar(), c != EOF && c != 'x') { switch (c) { case '\n': case '\r': printf ("Newline\n"); break; default: printf ("%c",c); } } return 0; }
我很好奇表达用作while循环的条件:
while (c = getchar(), c != EOF && c != 'x')
它的作用非常明显,但我以前从未见过这种结构。 这是特定于while循环吗? 如果没有,解析器/编译器如何确定逗号分隔表达式的哪一侧为while循环返回布尔值?
逗号运算符是一个二元运算符,它计算第一个操作数并丢弃结果,然后计算第二个操作数并返回该值。
它也是一个“序列点” ,这意味着所有副作用将在下一部分代码执行之前计算出来。
逗号运算符是一个奇怪的野兽,直到你理解它,并不是特定于while
。
表达方式:
exp1, exp2
计算exp1
然后计算exp2
并返回exp2
。
你经常看到它,虽然你可能没有意识到:
for (i = j = 0; i < 100; i++, j += 2)
你实际上并没有使用 "i++, j += 2"
的返回值"i++, j += 2"
但它仍然存在。 逗号运算符计算两个位以修改i
和j
。
你可以在任何可以使用普通表达式的地方使用它(例如你的函数调用中的逗号不是逗号运算符),并且它在编写紧凑的源代码时非常有用,如果这是你喜欢的。 通过这种方式,它是家庭的一部分,允许这样的事情:
while ((c= getchar()) != EOF) {...} i = j = k = 0;
等等。
对于您的具体示例:
while (c = getchar(), c != EOF && c != 'x')
发生以下情况:
-
c = getchar()
完全执行(逗号运算符是序列点)。 -
c != EOF && c != 'x'
被执行。 - 逗号运算符抛弃第一个值(c)并“返回”第二个值。
-
while
使用该返回值来控制循环。
在许多语言中,逗号是一个运算符,它总是产生第二个操作数的值。 从左到右依次评估操作数。
伪代码:
a = 10 print a = 7 + 8, a * 2
注意: print
被认为是不带参数的语句,因此后面的内容被认为是单个表达式a = 7 + 8, a * 2
。
执行方式如下:
- 第一行
- 把
10
放进去
- 把
- 第二行
- 评价
7 + 8
(15
) - 将评估值(
15
)放入a
- 评估
a * 2
(30
) - 使用操作数
15
和30
评估操作符:- 始终是第二个操作数的值(
30
)
- 始终是第二个操作数的值(
- 打印评估值(
30
)
- 评价
要在其他答案上进一步扩展,请在此代码中:
EXPRESSION_1 , EXPRESSION_2
首先评估EXPRESSION_1,然后有一个序列点,然后评估EXPRESSION_2,整个事物的值是EXPRESSION_2的值。
操作保证顺序和序列点对您引用的代码都很重要。 它们一起意味着我们可以确定在测试c的值之前调用getchar()函数并且完全更新变量c的值。
逗号是一个运算符。 它默认返回右手表达式的值 。 保证评估顺序先行,然后保持正确。
更新(回复Pax的评论):
就像大多数操作符一样,它可以为用户定义的类型重载:
#include #include using namespace std; enum EntryType { Home, Cell, Address }; class AddressBookEntryReference { public: AddressBookEntryReference(const string& name, const EntryType &entry) : Name(name), Entry(entry) { } string Name; EntryType Entry; }; AddressBookEntryReference operator,(const string& name, const EntryType &type) { return AddressBookEntryReference(name, type); } class AddressBook { string test; public: string& operator[](const AddressBookEntryReference item) { // return something based on item.Name and item.Entry. // just to test: test = item.Name; return test; } }; int main() { // demo: AddressBook book; cout << book["Name", Cell] // cool syntax! << endl; }