《高质量程序设计指南——C/C++语言》第4章 C/C++程序设计入门

第4章 C/C++程序设计入门

4.1  C/C++程序的基本概念

4.1.1、关于启动函数main()

      每个 C++ 程序都包含一个或多个函数,而且必须有一个命名为 main()的主函数。函数由执行函数功能的语句序列组成。操作系统通过调用 main() 函数来执行程序,main() 函数则执行组成自己的语句并返回一个值给操作系统。

1、 C++标准规定的标准main()函数的原型为:
    int main()  { /*....*/ } 

或      

    int main(int argc, char *argv[])  { /*....*/ }      

任何其它的形式都是非标准的,是特定实现的扩展形式,具有不可移植性。
2、main() 函数的返回值:

      在大多数系统中,main 函数的返回值是一个状态指示器。返回值 0 往往表示 main 函数成功执行完毕。任何其他非零的返回值都有操作系统定义的含义。通常非零返回值表明有错误出现。每一种操作系统都有自己的方式告诉用户 main 函数返回什么内容。

3、C++标准对main() 函数的限制:

1)不能重载;

2)不能内联;

3)不能定义为静态的;

4)不能取其地址;

5)不能由用户自己调用;

......

4.1.2、命令行参数    

int argc: 所有参数的个数(包括可执行文件本身的名称);

char *argc[]: 字符串指针数组(也常写成char **argc),按顺序包含可执行文件本身的名称和所有的参数。

 

4.1.3、内部名称

     C和C++语言实现都会按照特定的规则把用户(即程序员)定义的标识符(各种函数、变量、类型及名字空间等)转换为相应的内部名称。这就是所谓的”名字改编“(Name-Mangling)。

     标准C++的不同实现会采用不同的Name-Mangling方案(标准没有强制规定),这正是导致不同语言实现之间的连接器不能兼容的原因之一。

 

4.1.4、连接规范

    不懂!尽管看到过这样的代码,但实践中没有用过,也还没有遇到过这样的问题。以后会用了再补充。

4.1.5、变量及其初始化

1、变量的含义:变量就是用来保存数据的程序元素,它是内存单元的别名取一个变量的值就是读取其内存单元中存放的值,而写一个变量就是把值写入到它代表的内存单元中。C++中也称之为对象。

2、在C/C++中,全局变量(包括extern 和 static)存放在程序的静态数据区中,在程序进入main()函数之前创建,在main()函数结束之后销毁,因此在我们的代码中根本就没有机会初始化它们,于是语言及其实现就提供了一个默认的全局初始化器0。如果你没有明确地给全局变量提供初值(赋值),编译器会自动地将0转换为所需要的类型来初始化它们。

3,要区分“初始化”和“赋值”的不同:前者是发生在对象(变量)创建的同时,而后者是在对象创建后进行的。

4、全局变量的声明和定义应当放在源文件的开头位置。

4.1.6、C Runtime Library
      一般来说,一个C/C++程序不可能不使用C运行时库。

4.1.7、编译时和运行时的不同
      我们把编译预处理器、编译器和连接器工作的阶段合称为“编译时”。分清楚哪些构造在“编译时”起作用,哪些构造在“运行时”起作用非常重要。

4.1.8、编译单元和独立编译技术
     语言实现和开发环境所支持的独立编译技术并非语言本身所规定的。每一个源代码文件(源代码及其递归包含的所有头文件展开)就是一个最小的编译单元,每一个独立单元可以独立编译而不需要知道其他编译单元的存在和编译结果。


4.2 基本数据类型和内存映像
1、ANSI C标准没有布尔类型(bool)。大多C语言实现提供了BOOL类型:
typedef int BOOL;
#define TRUE  1
#define FALSE 0

2、关于NULL指针值:
   NULL是可以赋值给任何类型指针的值0,在C语言环境中它的类型是void*, 在C++中,它就是整数0。即:
#ifdef _cplusplus
#define NULL 0
#else
#define NULL ((void*)0)

     这是因为在标准C++中允许从0到任何指针类型的隐式转换。也因此,在C++中,很多程序员喜欢用0而不是NULL代表零值指针。


4.3 类型转换
    C/C++不会直接对两个类型不同的操作数进行运算,如果操作数类型不同,编译器就会试图运用隐式转换规则(通常是占用内存较少的类型会转换为占用内存较多的类型)。
    void 类型指针。
    隐式转换。
    强制转换。
4.4 标识符
4.5 转义序列
4.6 运算符
    试图熟记运算符的优先级是一种毫无意义的行为。如果代码行中的运算符比较多,应该用括号确定表达式中每一个子表达式的计算顺序,避免使用默认的优先级。然而,在一些面试题中,经常遇到这样的题目,真滑稽!
4.7 表达式
    这一节里,作者【建议4-1】:在使用运算符“&&”的表达式中,要尽可能把最有可能为假的子表达式放在“&&”的左边。而对“||”的表达式,则应该将最有可能为真的子表达式放在“||”的左边。理由是这样方法可以提高程序的执行效率。
    关于这个建议,现今的C++编码规范很少有这样的规定了,因为相对于可读性而言,这一点效率不值得。
    当然,如果子表达式本身的执行时间很长,以至于影响程序的效率。我们在做效率优化的时候使用这样方法则是很自然的事情。
4.8 基本控制结构
4.9 选择(判断)结构
1、【建议4-2】:在if/else结构中,要尽量把为真的的概率较高的条件判断置于前面,这样可以提高该段程序的性能。
      评:在不影响可读性的情况下,我赞同上述的建议!目前的C++编码规范中,更强调代码的可读性和可维护性。如果为了这一点判断效率,而牺牲可读性是不提倡的。当然,如果我们发现“条件判断表达式的效率”已经影响了程序性能,则另当别论。而且,记得Martin Fowler在《重构》一书中就有一节:用卫语句代替嵌套条件表达式,更是强调了用代码来表达意图。

2、关于“变量与零值的比较”。呵呵,尽管遵守使用吧,就不多说啦。
3、对if语句的补充说明
    作者提到了两个编码风格:
    1)if (NULL == var) 好于 if (var == NULL)
    评:由于受本书的影响,我经常采用第一种写法,但是每当我再次读到自己的这种代码时,总觉得这种写法怪怪的,很不爽,不知其他人是否有我同样的感受?

    作者这样做的理由是:if (NULL = var)不合法但if (var = NULL) ,所以可能会导致不经意的错误。的确是这样,但是现今的大多数编译器对 if (var = NULL) 这样的代码,都会提示警告信息。如果你提高警告级别,并遵循“在高警告级别下干净利落的编译你的代码”原则,我想作者的理由已经不再是理由。
   2)if (condition)
         return x;
      return y;
应该改写为:
      if (condition)
         return x;
      else
         return y;


   return condition ? x : y;
      评:我觉得三种写法都挺好的!更多情况下,我似乎使用的是第一种写法(即作者认为的不良风格)。最后一种写法确实简洁,但如果条件表达式和变量标识符都较长,这种写法可读性不太好,写成一行太长,写成两行别扭。哈哈,仁者见仁,智者见智吧!

4、switch语句

      ......

4.10 循环(重复)结构
     标准C/C++提供了三种循环结构:for,while,do/while。
     我偏爱for结构,因为它紧凑,简洁!而且你不太可能会忘记递增循环控制变量——而while会经常让你犯这样的错误。还有一点,如果循环体中出现了continue语句,while结构需要你多写一行代码——以确保循环控制变量被修改——而for不用——更郁闷的是我们常常忘记这一句代码。
     那么什么情况下使用while,我觉得用for实现起来有难度或感到别扭的时候,例如不确定循环(即循环控制条件会在循环体中发现改变)。
     作者用了较大的篇幅分析“循环语句的效率”,关于这一点,我没有做太多的试验。还是那句话,在第一次编写代码时,可读性优于性能。难道性能就不重要吗?额,重要!但那是优化阶段的事情。

4.11 结构化程序设计原理
4.12 goto/continue/break语句
     goto语句似乎已经变得无用,而且还会带来很多隐患和错误,因此有人建议去掉它,以绝后患。   

     不过,goto语句还是有一点可取之处:即它能从多层嵌套的循环体中嗖的一下子跳出来,用不着写很多次的break语句。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值