C语言条件语句中调用函数并赋值时的一个小坑
在C语言中,如果在条件语句中赋值,一定要注意符号优先级的问题,比较符号
是比赋值符号
先执行的。如果同时还调用函数,并将返回值赋给变量,更容易产生错误。
看下面的代码:
int increase(int a) {
return a + 1;
}
int main(int argc, char* argv[]) {
int count = 0;
while (count = func(count) < 10) {
// ...
}
return 0;
}
我希望循环执行10
次。但这段代码会陷入死循环。这是因为语句
while (count = func() < 10)
是先调用func(count)
,将其返回值与10
比较,然后将比较的结果赋值给count
。由于count
原始值为1
,所以func(count)
返回值为2
,2 < 10
是真,从而count
新赋值后为1
。之后,count
的值在每次循环都是1
,因此无法退出循环。
正确的写法,要么是加上括号:
while ((count = func(count)) < 10) {
// ...
}
但我个人认为这样写不是很好看,所以我更愿意写成:
do {
count = func(count);
// ...
} while (count < 10);
类似的情形是从TCP套接字中读取数据时:
while (str_len = read(client_sock, buf, BUF_SIZE) != 0) {
buf[str_len] = 0;
printf("Message from client: %s\n", buf);
}
假设客户端发送了字符串hello
,并已经全部到达本机的套接字缓冲区。第一次循环时,由于read()
返回值大于0
,所以str_len
值为1
,只会在屏幕打印h
。
由于str_len
为1
,所以会开始第二次循环,但实际上之前已经读到所有字符并存到buf
数组,只是在错误的地方加上了字符串结束符。此时套接字缓冲区已经为空,所以程序会在read()
函数处阻塞。
注意,缓冲区为空并不会使read()
返回0
,只有读取到客户端发送的EOF
(客户端关闭套接字时发送)才会使read()
返回0
。
正确的写法:
do {
str_len = read(client_sock, buf, BUF_SIZE);
buf[str_len] = 0;
printf("Message from client: %s\n", buf);
} while (str_len != 0)