C语言中&&运算符的求值顺序是否保证从左到右?——关于K&R《C程序设计语言》示例代码的疑问
关于K&R《C程序设计语言》中getline函数循环条件求值顺序的疑问解答
这是个非常精准且典型的C语言基础问题——很多学习者都会在这里混淆结合性和求值顺序的区别,咱们一步步拆解清楚:
核心原因:逻辑与运算符&&的短路求值规则
C语言标准明确规定,对于逻辑与运算符&&,其求值顺序是严格从左到右,并且具备「短路特性」:
- 先计算左侧表达式的值;
- 如果左侧表达式的结果为假(0),右侧表达式完全不会被求值;
- 只有当左侧表达式结果为真(非0)时,才会继续计算右侧表达式。
回到你提到的for循环条件:
for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i) s[i] = c;
这个条件是三个子表达式通过&&连接,所以执行顺序是固定的:
- 首先判断
i < lim - 1:如果数组已经快满了,直接终止循环,后面的读取字符操作都不会执行; - 若第一个条件成立,执行
(c = getchar()) != EOF:这里会先完成c = getchar()的赋值(读取一个字符到变量c),再判断该字符是否不是EOF; - 若第二个条件也成立(读取到的不是结束符),才会执行
c != '\n':此时的c就是刚刚读取的那个字符,用来判断是否是换行符。
关于你假设的“顺序颠倒”情况
你担心的「c != '\n'先于(c = getchar()) != EOF求值」的情况不可能发生,因为&&的左到右求值顺序是C标准强制要求的。
退一步说,如果真的出现这种不符合标准的情况,后果确实如你所想:判断换行符时用的是上一次循环中读取的旧c值,而不是当前刚读取的字符——这会导致程序逻辑完全混乱,比如可能提前终止循环(用上一次的换行符判断),或者错误地把换行符存入数组。
为什么K&R的代码能广泛正常运行
因为这段代码依赖的是C标准中明确规定的&&运算符行为,而非编译器的特定实现。所有符合C标准的编译器都会遵循这个求值规则,所以这段代码是可移植的,能够在各种环境下正常工作,这也是它被广泛引用的原因。
最后再区分一下你提到的「结合性」和「求值顺序」:
- 结合性是指多个相同运算符的分组方式(比如
&&是左结合,a&&b&&c会被解析为(a&&b)&&c); - 求值顺序是指表达式的计算顺序,
&&的左到右求值+短路特性是标准单独规定的,和结合性是两个完全不同的概念。
内容的提问来源于stack exchange,提问作者just_chilling




