C语言/C++基本语句编程风格

简介: C语言/C++基本语句编程风格

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


基本语句编程举例


if语句


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


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


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


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


if(flag)//表示flag为真

if(!flag) //表示flag为假

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


if(flag == TRUE)
if(flag == FALSE)
if(flag == 1 )
if(flag == 0 )

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


if(value == 0)

if(value != 0)

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


if(value)

if(!value)   //会让人误解value是布尔变量

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


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


if(x == 0.0)  //隐含错误的比较

转化为


if((x >= -EPSINON) && (x <= EPSINON))

//其中EPSINON是允许的误差(即精度)。

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


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


if(p == NULL)

if(p != NULL)   //p与NULL显式比较,强调p是指针变量

不要写成:


if(p == 0)

if(p != 0)    //容易让人误解p是整型变量

或者


if(p)

if(!p)    //容易让人误解p是布尔变量

(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)
    return x;
return y;
改写成
if(condition)
{
    return x;
}
else
{
    return y;
}

或者改成更加简练的:


return(condition ?x:y);

循环语句的效率


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


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


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


for(row = 0; row < 100; row++)
{
   for(col=0;col<5;col++)
   {
      sum = sum +a[row][col];
   }
}

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


for(col = 0; col < 5; col++)
{
   for(row=0;row<100;row++)
   {
      sum = sum +a[row][col];
   }
}

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


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


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


for(i = 0; i < N; i++)
{
if(condition)
    DoSomthing();
else
    DoSomthing();
}

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


if (condition)
{
    for (i=0; i<N; i++)
        DoSomething();
}
else
{
    for (i=0; i<N; i++)
      DoSomething();
}

(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++)

{

}

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


for(int x = 0;x <= N-1; x++)

{

}

switch语句 switch是多分支选择语句,而if语句只有两个分支可供选择。虽然可以用嵌套的if语句来实现多分支选择,但那样的程序冗长难读。switch 语句基本格式:


switch(variable)
{
    case value1:
                  break;
    case value2:
                  break;
        default:
    break;
}

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


goto语句


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


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


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


例如:


goto state;
String s1, s2; // 被 goto 跳过
int sum = 0;   // 被 goto 跳过
state:

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


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


{

{

  {

    goto error;

  }

}

}

error:

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


小结


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


相关文章
|
4天前
|
存储 Linux C语言
c++进阶篇——初窥多线程(二) 基于C语言实现的多线程编写
本文介绍了C++中使用C语言的pthread库实现多线程编程。`pthread_create`用于创建新线程,`pthread_self`返回当前线程ID。示例展示了如何创建线程并打印线程ID,强调了线程同步的重要性,如使用`sleep`防止主线程提前结束导致子线程未执行完。`pthread_exit`用于线程退出,`pthread_join`用来等待并回收子线程,`pthread_detach`则分离线程。文中还提到了线程取消功能,通过`pthread_cancel`实现。这些基本操作是理解和使用C/C++多线程的关键。
|
1天前
|
C语言 图形学 C++
|
11天前
|
编译器 C++
Essential C++ 第2章 面向过程的编程风格
Essential C++ 第2章 面向过程的编程风格
|
12天前
|
C语言 C++ 编译器
【C++语言】冲突-C语言:输入输出、缺省参数、引用、内联函数
【C++语言】冲突-C语言:输入输出、缺省参数、引用、内联函数
【C++语言】冲突-C语言:输入输出、缺省参数、引用、内联函数
|
1天前
|
程序员 C语言 C++
【C语言】:柔性数组和C/C++中程序内存区域划分
【C语言】:柔性数组和C/C++中程序内存区域划分
4 0
|
1天前
|
C语言 图形学 C++
|
11天前
|
算法 编译器 C++
Essential C++第4章 基于对象的编程风格
Essential C++第4章 基于对象的编程风格
|
12天前
|
C语言 C++
【C++语言】冲突-C语言:命名空间
【C++语言】冲突-C语言:命名空间
|
19天前
|
程序员 C语言 C++
C语言学习记录——动态内存习题(经典的笔试题)、C/C++中程序内存区域划分
C语言学习记录——动态内存习题(经典的笔试题)、C/C++中程序内存区域划分
35 0
|
27天前
|
安全 Linux 编译器
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)(下)
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)
23 0