白话C语言:冷门的逗号运算符

逗号运算符的用法

逗号运算符(comma operator)是C语言中使用率比较低的一个运算符,不过它也有自己的特点:它是C语言中优先级最低的运算符(这点挺重要的)。

逗号运算符是一个二元运算符,语法格式如下:

expression1, expression2

如上所示,它的作用就是连接两个表达式,第一个子表达式(expression1)会先求值,第二个子表达式(expression2)后求值,然后第二个表达式的结果会作为整个逗号表达式结果。直接上例子:

a + 5, b + 4 // 先计算a+5,再计算b+4,整个表达式的结果是b+4

逻辑非常简单,不过由于逗号在C语言中也作为分隔符来使用,要注意区分,比如如下情况,里面的逗号不一定是逗号运算符,可能只是分隔符:

func1(x, y + 2, z );        // 这里没有逗号运算符,只是函数调用
func2((x + 1, y + 2), z );  // 先计算逗号表达式(x + 1, y + 2), 再调用函数,函数的参数是(y+2, z)
int a=1, b=2, c=3, i=0;     // 这里逗号是分隔符,所以也没有逗号表达式
enum letter {A, B, C, D};   // 定义枚举,这里也没有逗号表达式

逗号表达式可以连续使用,它是从左到右结合的,所以连续使用的话整个表达式的值是最后一个表达式的值:

a + 5, b + 4, c + 3, d + 2 // 等于((a+5, b+4), c+3), d+2,整个表达式的值为d+2 

来一个例子试试:

#include <stdio.h>
int main () {
   int i = 10, b = 20, c= 30;
   i = b, c;
   printf("%i\n", i);  // 输出20

   i = (b, c);
   printf("%i\n", i);  // 输出30
}

如果看到结果的第一眼有点懵的话,那么请回想下逗号表达式的优先级:它的优先级是最低的,比赋值运算符还低。所以i=b, c​结合之后是(i=b), c​,整个表达式的值是c,但是没有赋值给任何变量;i的值因为i=b​这句赋值变成了20。而下面的i=(b,c)​才是将b, c​的结果赋给i​。

什么时候需要使用逗号运算符

逗号运算符的用法和特点相信你已经了解,不过你是否有个疑问,就是这个运算符是用来干啥的?怎么感觉没什么用呢?

逗号运算符确实用途不广,不过C语言当然不会设计一个无用的运算符,我们先总结下它的特点吧:

  • 可以把两个或者多个(连续使用的情况)表达式合成一个表达式;
  • 每个子表达式都会执行,而且保证执行的顺序
  • 最后一个子表达式的结果作为整个逗号运算符的结果。

所以,当你需要在代码中的某处执行多个表达式,但这里又只能放入一个表达式的时候,就可以用逗号运算符来解决。这也解释了为什么逗号运算符的优先级必须最低,因为它必须尽量不干扰其内部的子表达式,优先级定为最低才能实现这一点。同时,由于第一个子表达式的计算结果被忽略,第一个子表达式通常会进行赋值或者函数调用等具有副作用的操作,而不是单纯的计算。

让我们看下逗号表达式的几种使用场景。

用于for循环中

for(i = 0, j = 10; i < N; j--, i++) {
  // ...
}

for循环的三个表达式都可以使用逗号表达式。

用于while循环中

char c;
while(c = getchar(), c != '\n') {
    // ... do something
}

如果不使用逗号表达式,可能就要繁琐一些:

char c = getchar();
while(c != '\n') {
    // ... do something
    c = getchar()
}

给断言(assert)添加更多信息

如下代码:

#include <stdio.h>
#include <assert.h>
int main () {
    int i = 10;
    assert( ( "i is too big!", i <= 5 ) );
}

执行到assert处,报错如下:

Assertion failed!

Program: D:\test_src\codeblocks_hello\codeblocks_hello\bin\Debug\codeblocks_hello.exe
File: D:\test_src\codeblocks_hello\codeblocks_hello\main.c, Line 6

Expression: ( "i is too big!", i <= 5 )

相当于给断言语句增加了注释。

其他"可以,但没必要"的应用场景

用于if语句:

if (y = f(x), y > x) {
    // ...
}

用于省略语句块:

if (x == 1) y = 2, z = 3;

// 等价于

if (x == 1) {y = 2; z = 3;}

这两种使用场景必要性不是很大,没有省太多事儿,反而影响代码可读性。

未完待续的内容

关于逗号运算符,还有一些额外的知识以及使用场景本文没有提及。这主要是因为这部分内容比较复杂了,本节主要还是介绍比较基础的用法,相关的内容后续会在其他章节中讲到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值