你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C进阶技巧——逗号表达式

[复制链接]
gaosmile 发布时间:2020-7-9 12:14
1、先来一个逗号表达式例子
一个逗号表达式的实例:
1#include <stdio.h>
5 w7 k6 o3 e5 S9 {- [$ U4 @( w# ` 2#include <stdlib.h>, q* w, C/ v* e; d
3/******************************************) ~5 a( A) z8 G9 Q. ]
4 * Fuction: Main 7 T  z6 q/ S$ w  f+ m$ r+ `
5 * Descir : 测试一个逗号表达式   b0 e% k6 [- C: f3 \# ?) t
6 * Author :(公众号:最后一个bug) # [0 t3 x$ D3 q: B# @! q7 `. Z$ z
7 *****************************************/
+ v$ _) y4 D- G: u) t; T; ~' j6 W 8int main(int argc, char *argv[]) {/ c; V3 K2 ?" L6 {9 A$ m8 s
9    int Val = 1;+ F' h  E7 z4 t
101 f, c) E2 G; F7 J7 i& N
11    Val = ++Val,Val+10,Val*10; //逗号表达式
; c' A. m; x& y2 b7 {: V12
: G7 L: V9 E: a' O6 y% X8 }13    printf("Val = %d",Val);* U# u: h' f. T
14
+ C% g$ N! Y2 e; {& l% ^) E- A15    return 0;7 [6 m2 ?% u8 }4 _" t
16}
0 D/ F1 y" }6 I0 H5 B
分析一下:
    大家首先可以自己算一下最后输出的结果,然后再去看下面的答案,其实对于逗号表达式的语法规则并不是很难,主要是大家在平时的开发中使用得比较少,一旦经常不使用就容易淡忘。
* A! M$ Z- E1 |% }) q
    逗号表达式的形式 : 表达式1,表达式2,......,表达式n
三点搞定:
  • 逗号表达式从表达式1开始顺序从左向右执行;
  • 其逗号表达式最后的值为最后一个表达式的值;
  • 逗号运算的优先级最低,也就说明与其他运算符结合使用的时候,在没有括号的情况下逗号运算符最后才执行。

    8 B; z+ R; U) o6 p3 R
上面例子的结果:
微信图片_20200709121044.png
    可能有部分小伙伴算出的结果是10,主要是没有考虑其逗号表达式优先级最低,所以第一赋值表达式优先执行。

  N  O; @" f. E3 Q* c4 {
2、"不怎么用"是不是就"没有用?

/ c1 [; v7 O* }% c5 q8 f
    既然大家平时都用得不多,是不是这个逗号表达式就是多此一举呢 ? C发展这么多年,如果真的没有价值估计早就不存在了吧,所以还是要秉承着"存在即是合理"的态度看待逗号表达式。
   
微信图片_20200709121049.png
' d$ k. T7 }2 a
    大家在平时阅读代码的时候应该都是按照从左至右,然后从上至下来的方式吧。基本上一个分号结束一行的书写,由于电脑屏幕的限制,有效代码暴露在人的视野中是有限的,同时人瞬间记忆时间也是有限的,如果在一个小小的屏幕上阅码势必会阻碍程序员的阅读和理解,比如下面两种书写方式:

- r8 [3 B* a1 P/ g
1/******************************************
' i" r1 C2 @2 V0 N) x 2 * Fuction: 非逗号表达式书写 ' T, U& z9 s" b$ G; v. u$ r% m! }* C
3 * Descir :
$ X" W3 L3 F% m# }  c* I7 `4 g 4 * Author :(公众号:最后一个bug)
/ E7 |. y- ~! X+ m; F 5 *****************************************/
* s6 Y' }; T6 w  c 6if(IsOk())8 L# G2 g9 p0 K' _$ i! q
7{
: h, w; ^' @8 r& V7 N; T6 Y 8    sOkProc();- Q8 |/ @. v' [7 r9 a& L
9    return GetOkCode();
$ n+ s5 e( b, ]8 I$ s, I10} ! ]/ K+ E9 u- m2 F& h" g
11else% @& Y3 b; D& }' f" J% P8 y
12{! @% B8 ~+ p/ p1 N
13    sNoProc();
$ m' J; L/ _* e; S! C14    return GetNoCode(); & @$ R1 y: ~" k5 e( v
15}
8 T3 [4 L/ `4 h# |8 Q0 x16/******************************************; M0 |+ y' L3 Y3 d3 I
17 * Fuction: 采用逗号表达式书写 # Z+ k9 O+ K5 }) O% o2 |$ W
18 * Descir : 9 `; ]( P; `6 O' ]# P
19 * Author :(公众号:最后一个bug)   S2 i' \* M" K) M* h8 l
20 *****************************************/ $ I) ]6 S# X# X8 M
21return (IsOk())?(sOkProc(),GetOkCode())sNoProc(),GetNoCode());
分析一下:
  • 上面是两种代码书写方式,第一种占据了多行,而第二种进占据一行,这样同样一个屏幕所容纳的有效代码第一种就明显少于第二种方式,所以很多程序员都会选择使用一种大长屏或者多屏进行开发。
  • 第二种方式似乎很多小伙伴觉得代码不够美观,也不便于维护,其实这仅仅只是一种习惯罢了,就好像编码的时候 : 第一个大括号是否需要另外起一行,或者是使用==号一定要像if( 1== b)这样把数据放左边,当你习惯了这种编码风格也会觉得用第二方式来得直接。
    5 r2 l; e" H& b+ ?/ f& x
     
3、逗号表达式常用的地方

2 y4 H) \/ ?3 D4 H6 P5 l. a7 q/ e
    下面为大家介绍几个用逗号表示式比较多的地方:
+ r4 o% t8 B; W" G" E7 x
1、for循环中的处理
参考demo:
1#include <stdio.h>6 G+ t3 ~$ e" s7 z
2#include <stdlib.h>
1 R, X4 f, W" H; |. K% S5 N1 P 3#define  ROW_NUM  (5)
% t# n/ M- l- ?  N1 Q9 f 4#define  LINE_NUM (5) 6 d& Y8 {1 K; u' _7 j0 z# g
5/******************************************$ N9 R1 c9 X$ M$ \) J& o! f6 X
6 * Fuction: Main
! p$ P1 o% a1 c 7 * Descir :for 遍历查找 # m* b) L! K' S5 u' c  u
8 * Author :(公众号:最后一个bug) ( u% ?* X! T' R3 n. e9 [
9 *****************************************/ 4 O7 b* O4 g! M' I% C# F
10int main(int argc, char *argv[]) {
1 ~  O  j8 s  E# Z. b; u11    int i = 0,j = 0;
' Y) }# j, Z4 r8 c8 v0 C12    int Matrix[ROW_NUM][LINE_NUM] ={{1,1,1,1,1},\6 P9 f5 z0 {1 x
13                                    {2,2,2,2,2},\
0 A7 F' ]* R3 ]) O7 j  z6 [  B" V14                                    {3,3,3,3,3},\7 f& S$ k3 k1 k5 G: e# E' [
15                                    {4,4,4,4,4},\% x* D+ o2 L0 J: M2 ~% M
16                                    {5,5,5,5,5},\
; C7 G, R, L1 B! j# z, U17                                    };
% I0 c" f0 X  {9 H3 X1 ^185 J3 c7 k+ q. t% z( v6 a0 w
19    for(i = 0,j = 0;(i < ROW_NUM)&&(j < LINE_NUM);i++,j += 2)
, }# \3 x7 J/ g+ u6 w$ e' P20    {
. _# x$ f- R& f+ m21         printf("Matrix[%d][%d] = %d\n",i,j,Matrix[j]);
/ J! ?* F# C' t' r22    }
. A# h  I  X5 s8 V4 Y* @23    printf("公众号:最后一个bug\n");
. L' w' k; S- s" [: z24    return 0;
5 y. |0 ^& Q9 a  K$ _, K25}
分析一下:
  • 上面在for循环中遍历相关数据几比较常规的处理,也是逗号表达式经常出现的地方,这样的表现形式让代码更加简单明了。
  • 其结果如下:
    7 @8 S1 Z' i/ u9 G% B( H6 ]$ n
微信图片_20200709121055.png

" k+ Y* \( X( y5 {0 ]
2、弱化++处理
    大家应该都知道++在前先执行自加,然后再进行相应处理,而++在后则相反,那么我们可以使用逗号运算符优先级最低的特点来弱化该问题,避免编码出现bug。
参考Demo
1#include <stdio.h>" u& v, c9 @$ w6 w$ ^2 B
2#include <stdlib.h>! \$ c1 E/ V# x* W. r* \) s8 K4 ]
3/******************************************
- ^5 ^* X4 h* ~# s' P 4 * Fuction: Main
0 B% C& N4 G6 l1 ^, w 5 * Descir :弱化++前后问题
0 I0 X7 U3 O# ?  c' p 6 * Author :(公众号:最后一个bug) 5 ^) ]8 W2 x9 j- z
7 *****************************************/
, G- B7 a! L7 X0 N, i6 N6 B& @) b 8int main(int argc, char *argv[]) {
* C3 L0 l! Y7 ~4 X/ X' ] 9    int i = 0;
. Y3 N2 `. n1 o8 `0 {( ~. o10
8 C, m9 @4 R% V6 Y7 f) o11    //1、常规操作+ p8 c9 m8 P, }8 F+ i
12    i = 0;
. a& v9 x! i+ n0 X6 C: P5 I. H13    while(++i < 3)7 m$ x7 S  C' J2 U, a
14    {
# _# d' ^: ]0 l4 [8 q0 Z3 i1 z15        printf(" i = %d\n",i);2 C# O, p; h; c4 |
16    }* T2 g: s6 _2 o) @- G3 k  v
17    printf("*****************\n");# Z$ m- J0 A8 n( L8 l8 E5 Y
18" ~( s3 z: |5 Y' {# I& O* ?( m
19    i = 0;
- d6 ^, U0 N# b& v4 [20    while(i++ < 3), \: a( {) u* b  ]
21    {
0 L! z  D' @: K; b  {4 x22        printf(" i = %d\n",i);
2 t. \* P( O8 e" W- k& e5 K23    }
8 R. @  Q2 g. B. K3 R/ B24    printf("*****************\n");3 ~9 I8 `4 |9 j* v8 M
25
( ^4 U. c6 j! A: C9 N26    //2、逗号表达式处理一下
+ G  F. r1 n& s+ ]: {3 w27    i = 0;+ e0 B6 c, C/ P
28    while( i++,i < 3)
% {6 i# O, _/ v! H, `$ q- |29    {
* y( U1 G- D# S- y9 D; R# D30        printf(" i = %d\n",i);
! j3 P+ E* s3 ]8 Y' z6 c: j9 P31    }# ^' P7 F3 g4 u* M: |  V+ |
32    printf("*****************\n");
1 H2 O" Y. t6 `, E" P- g33
, k* n! ]. t/ k$ L34    i = 0;
1 G7 @- E2 q" Z* M/ E35    while( ++i,i < 3)6 {8 U  H" I/ p2 E
36    {
. m6 ]" F% F/ x9 I" l1 J( ^0 u37        printf(" i = %d\n",i);8 K* a% ^3 A/ {- a
38    }
8 K: X9 I& T6 r, W- m39    printf("*****************\n");* j1 L+ D2 v1 S; L! o) B( X
401 H. \+ e+ [; ?$ v$ h% a: E2 P( o
41    printf("公众号:最后一个bug\n");
. C, G7 A9 H" N& H42    return 0;9 F; L  q& A; `, J% q
43}
" R5 h# C& X2 d4 o! a* h44
分析一下:
  • 当使用逗号表达式以后,不管++在前还是在后,其都会自增加1,然后再进行右边表达式的处理,这样就不用担心是不是多记了一次,导致各种问题。
  • 运行结果:
    7 S5 p9 w& L6 y9 `" Y
. J; j% Z9 B+ s$ z4 V1 [, k  p, G" F
微信图片_20200709121059.png
, \% p; c7 z9 a- j2 r2 i& G9 e
" j( ]- _# I0 F2 S' }) ?
3、更加精简宏定义
参考demo
1#include <stdio.h>5 F# X; a: N+ L- }
2#include <stdlib.h>8 _" T" J! s# A$ e$ X# l- v6 U
34 Z$ W! I7 I; j( Z
4#define  GET_INDEX(a ,b)  ( a+= 2,a + b)
5 L9 c& {5 m. D9 u: r1 Y 5/******************************************
# H, S8 q, a1 L( M 6 * Fuction: Main 6 a9 K& a" R- t/ ?
7 * Descir : 简化宏 % z9 Z9 w3 K* R7 k+ H1 x
8 * Author :(公众号:最后一个bug) 7 ^8 n7 A5 _1 J; Z7 z. _* m7 A
9 *****************************************/ 3 c( y1 k; C% l4 U! ]
10int main(int argc, char *argv[]) {$ h8 J9 T* F$ `, ^: r6 m$ o
11    int i = 0,Val = 0;' L% Y# r2 [$ s7 {
12    int Param1 = 0, Param2 = 0;+ L; }, {( N7 p5 Y9 n7 ?% W
13    int Matrix[5] ={5,5,5,5,5};  ~' r$ H! E, @
14
$ F% s5 J. k. t9 X- k15    printf(" Matrix = %d\n",Matrix[GET_INDEX(Param1,Param2)]);
9 e' l' W+ K6 m" q6 O! ~16    printf("公众号:最后一个bug\n");
% B: s9 ?* M3 V% F5 m17    return 0;
# b* f, B5 M) w% L, r# G18}

; K# {# |- r# |
分析一下:
  • 逗号表达式最终还是一个表达式,所以它可以直接用在几乎所有变量可以用的地方,这是和语句不同的。
  • 所以逗号表达式左边的表达式可以预先进行各种处理,其最右边的表达式相当于返回最后的结果,从而减少函数的封装和调用。
    8 ~3 A% M. h% `& n" J' p

5 _0 j2 v4 [) K# J- W7 Y0 e0 Y
4、最后小结

  W' z$ b% V; R" ^! @% B) c6 z- Z1 u9 ~
    逗号表达式其实就是横向编码的一种方式,能够让程序员更好的利用一行的空间,使得代码更加紧凑,所以使用逗号表达式并没炫技,而是增强了代码的灵活度,不过话说回来逗号表达式在C混乱编码大赛上的使用频度是非常之高的。

: ?: K/ v+ @' Z1 I5 e9 V
赞 收藏 评论1 发布时间:2020-7-9 12:14

举报

1个回答
goyhuan 回答时间:2020-7-9 13:48:06
小小的逗号用处很奇妙
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版