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

C语言/C++使用语句的一些规则和建议

[复制链接]
gaosmile 发布时间:2020-6-8 20:25

初学者阶段编程时,编写基本语句可能会有隐含错误的方式,基本语句主要针对if、for、while、goto、switch等,它们看似简单,但使用时隐患比较多,本文归纳了使用语句的一些规则和建议。

基本语句编程举例
  • if语句


    4 w$ N; Z& p- ?2 t& {2 u& m7 `

if语句是C++/C语言中最简单、最常用的语句,然而很多编程人员用隐含错误的方式写if语句,本文以“与零值比较”为例,进行讨论。

(1)布尔变量与零值比较:不可将布尔变量直接与TRUE、FALSE或者1、0比较。根据布尔类型的语义,零值为“假”(记为FALSE),任何非零值都是“真”(记为TRUE)。TRUE的值究竟是什么并没有统一的标准,

例如VC++将TRUE定义为1,而VB则将TRUE定义为-1。

假设布尔变量名为flag,它与零值比较的标准if语句如下

if(flag)//表示flag为真2 U# |$ h+ @* w. h2 e9 ]. [
if(!flag) //表示flag为假

7 i1 B/ ^5 P1 v/ Z( n- x/ L

其他的用法都属于不良风格,例如:

if(flag == TRUE)
, D9 y+ y9 v: [: a/ \2 q4 nif(flag == FALSE)0 _, Z5 G+ M+ S; z
if(flag == 1 )
+ J% O* N1 O/ }: |7 Mif(flag == 0 )
$ m( G0 `) X: l& g

(2)整型变量与零值比较:应当将整型变量用“==”或“!=”直接与0比较。假设整型变量的名字为value,它与零值比较的标准if语句如下:

if(value == 0)1 A1 X2 R, j2 J% Y! d# g! s& a; g
if(value != 0)
! y& y, J! n5 F4 g8 u" }; H7 D

不可以模仿布尔变量的风格而写成:

if(value)6 d# ~8 `0 S7 W" a9 E  D8 x
if(!value)   //会让人误解value是布尔变量

) ?& A9 ]" j3 i$ S3 U

(3)浮点变量与零值比较:不可以将浮点变量用“==”或“!=”与任何数字比较。

千万留意,无论是float还是double类型的变量,都有精度限制,所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。假设浮点变量的名字为x,应该将

if(x == 0.0)  //隐含错误的比较
! Q; ?; X5 X2 F( H! w" ~: u" O

转化为

if((x >= -EPSINON) && (x <= EPSINON))
6 @+ z# q# l/ x" a- x//其中EPSINON是允许的误差(即精度)。
6 E! s3 [4 A0 H4 e4 k& |

(4)指针变量与零值比较:应当将指针变量用“==”或“!=”与NULL比较。

指针变量的零值是“空”(记NULL)。尽管NULL的值与0相同,但二者的意义不同。假设指针变量名p,它与零值比较的标准if语句如下:

if(p == NULL)4 Q3 r3 S0 ]7 g( f* c2 W
if(p != NULL)   //p与NULL显式比较,强调p是指针变量

& U7 S+ M" C  e) f1 v# U/ b

不要写成:

if(p == 0)
. P6 I) c5 g% A5 Eif(p != 0)    //容易让人误解p是整型变量

2 @' D3 v  P- k9 E

或者

if(p)
, h9 k5 d. w2 \9 aif(!p)    //容易让人误解p是布尔变量
7 s8 X8 p3 q2 F

(5)对if语句的补充说明

有时候可能会看到if(NULL == p)这样古怪的格式。这样写能够防止将if(p == NULL)误写成if(p = NULL),而有意将p和NULL颠倒。编译器认为if(p = NULL)是合法的,但会指出if(NULL = p)是错误的,因为NULL不能被赋值。程序中有时会遇到if/else/return的组合,应该将如下不良风格的程序:

if(condition)' `. ?& B7 W, T! a9 S$ ~3 S
    return x;1 ~, q4 \, C( ?
return y;

1 z4 Z- h& j2 _2 k! H( o

改写成

if(condition)
9 R- G4 G' Y: Z- D; N- b5 i{4 J; a1 H/ w  B4 a$ l+ e2 \
    return x;
6 y# o# ^, d* [# _8 Y1 Y7 j}# y% m  Q1 a1 `7 w' |# V( e
else) f' z, Y6 ^: M! C* u1 K- x
{4 F; A# k9 r/ `, T: N
    return y;
- r2 J' R; h  V& E6 x- H}
4 N# ?4 H- M1 Y8 A2 f

或者改成更加简练的:

return(condition ?x:y);- l" Z* S# q- w% w/ ~& ~
  • 循环语句的效率


      G" N, G& E- y: z) n

C++/C循环语句中,for语句使用频率最高,while语句其次,do语句很少用。提高循环体效率的基本方法是降低循环体的复杂性。

(1)在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。例如下面代码示例b的效率就比示例a的高。

示例a:低效率(长循环在最外层)

for(row = 0; row < 100; row++)( A  j" s# y* Q8 a
{
, n" T& M8 {% }* ]   for(col=0;col<5;col++); n0 t% d; }% [) \$ O
   {
7 X+ x# ]5 J8 \+ z4 [2 a6 x      sum = sum +a[row][col];
3 H1 N% d, k' t1 v% y   }7 @& P; e% ?' s% C4 ]6 A
}
: N, z/ `1 c& F2 k8 e

示例b:高效率(长循环在最内层)

for(col = 0; col < 5; col++)
+ Z( J# c- {& q+ C# i{& [+ A" [. O: p2 r: P- q0 _
   for(row=0;row<100;row++)
! r6 S1 }+ G8 g1 A   {
/ W9 t0 f1 E1 V6 [      sum = sum +a[row][col];4 ^  p8 K% v! d4 q5 O
   }
0 s$ d6 `( S3 b( i# A1 P}

" M$ ?- Z! {/ H* K0 u

(2)如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外面。

示例c的程序比示例d多执行了 N-1 次逻辑判断。并且由于前者老要进行逻辑判断,打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。如果 N 非常大,最好采用示例 d的写法,可以提高效率。如果 N 非常小,两者效率差别并不明显,采用示例 c的写法比较好,因为程序更加简洁。

示例c:效率低但程序简洁

for(i = 0; i < N; i++)
' v4 W9 V  |6 I1 Y) l: [{" r& X" e+ S7 O# ?
if(condition)
. x, F1 E4 B2 d4 f8 [* J+ @    DoSomthing();& m& t* I5 M  p+ U' I# ^' R
else
- I4 ?' @  ^( q) l. ^3 u0 _, W7 c    DoSomthing();9 S5 r; D( G! r. n# S
}
3 C( F* x4 I7 l4 a

示例d:效率高但程序不简洁

if (condition)
$ g  O1 s1 b9 @{
8 |5 s" d! _0 i+ N    for (i=0; i<N; i++)3 W1 F' g* N& I0 B* M1 i0 J
        DoSomething();
. ~" c9 P/ w4 k: a' B. c; n}4 s; ?: q2 |, `1 I  J6 w
else7 y0 m; q) l1 N5 Z5 `
{
9 x, U1 D, O; p/ w1 Q" ?; p/ n+ M    for (i=0; i<N; i++)
( C8 H) Z) W" n3 S  Z3 e5 |8 z4 w      DoSomething();1 h7 _1 c" a1 @  c6 o
}
$ {6 Z5 w$ M& P5 F- y7 |# M

(3)for语句的循环控制变量

不可以在for循环体内修改循环变量,防止for循环失去控制。

建议for语句的循环控制变量的取值采用“半开半闭区间”写法。

示例e中的x值属于半开半闭区间“0=<x<N”,起点到终点的间隔为N,循环次数为N。示例f中的x值属于闭区间“0=<x<=N-1”,起点到终点的间隔为N-1,循环次数为N。相比之下,示例e的写法更加直观,尽管两者的功能是相同的。

示例e:循环变量属于半开半闭区间

for(int x = 0;x < N; x++)
- v- Z1 I! k0 h2 j* c6 G' T: I{
. Z/ A* w: H5 {' q}

0 k, i& u$ D3 t' e( E

示例f:循环变量属于闭区间

for(int x = 0;x <= N-1; x++)
9 f1 e7 ?4 Y  n" F{
: Y9 }% M7 I' K" h  l% z+ _: V9 l}
4 h2 r% k, C0 d4 f
  • switch语句 switch是多分支选择语句,而if语句只有两个分支可供选择。虽然可以用嵌套的if语句来实现多分支选择,但那样的程序冗长难读。switch 语句基本格式:

    ) b- }. x, W' s9 O1 P5 f' L
switch(variable)) Z0 R) o: k- j& L' {
{8 S& _% x+ I4 u5 u
    case value1:" b# y1 h5 l' [7 G3 A) L) R: ~
                  break;
& ?: ]/ B: ~/ o9 |6 G% ^    case value2:, y2 o5 R, _5 W- u
                  break;3 T3 M) Z; M; @: N2 E' Q2 g
        default:  Q/ x0 x3 R' I7 r: d! X, B
                  break;
  ]# Y6 T% ~  v7 |* r}

2 d- h4 e+ X, a4 ^+ J$ p

每个 case 语句的结尾不要忘了加 break,否则将导致多个分支重叠(除非有意使多个分支重叠)。不要忘记最后那个 default 分支,即使程序真的不需要 default 处理,也应该保留语句 default : break; 这样做并非多此一举,而是为了防止别人误以为你忘了 default 处理。

  • goto语句

    8 g; z  ?5 ?9 u& J) j; j

自从提倡结构化设计以来,goto 就成了有争议的语句。

  • 由于 goto 语句可以灵活跳转,如果不加限制,它的确会破坏结构化设计风格。

  • goto 语句经常带来错误或隐患。它可能跳过了某些对象的构造、变量的初始化、重要的计算等语句,


    ; K& J% @; p3 W9 g8 n% X( h1 R4 R" H

例如:

goto state;
! j$ i, l; A: Y7 s& R( R7 c( n4 TString s1, s2; // 被 goto 跳过- S4 {' U8 F0 x/ b
int sum = 0;   // 被 goto 跳过
" A% {* I) j5 s. d* ~( K; istate:

; ?0 }! q7 R; S

如果编译器不能发觉此类错误,每用一次 goto 语句都可能留下隐患。很多人建议废除 C++/C 的 goto 语句,以绝后患。

但实事求是地说,错误是程序员自己造成的,不是 goto 的过错。goto 语句至少有一处可显神通,它能从多重循环体中一下子跳到外面,用不着写很多次的 break 语句; 例如:

{% [, _5 G  {! c! ]) O
{4 x/ m# H3 c- `( B1 d- d1 n2 D% y$ K
   {* [1 ~3 z# X( a6 `# D" p
     goto error;
, H. l0 W4 `$ Y5 n& u5 `- p" T- z   }
2 N" w/ ]7 o0 q! w; [7 ~0 r }
) V1 j# B/ W1 W}) R$ X3 Q5 ^6 ^! |6 g
error:

. t% p  `( Q$ H; d/ f: G0 g9 [6 o

就像楼房着火了,来不及从楼梯一级一级往下走,可从窗口跳出火坑,所以我们主张少用、慎用 goto 语句,而不是禁用。

小结

主要针对if、for、while、goto、switch等基本语句使用时可能出现隐患问题,归纳了正确使用它们的一些规则和建议。如有不对留言指正 参考资料:林锐《 c/c++编程指南》


0 v1 H& ^* b, A6 P$ |4 G
赞 收藏 评论0 发布时间:2020-6-8 20:25

举报

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