《C专家编程》读书笔记2

第二章  这不是Bug,而是语言特性

 

2.1       这关语言特性何事,在Fortran里这就是Bug呀

 

        一个‘L’的NUL用于结束一个ASCII字符串

        两个‘L’的NULL用于表示什么也不指向(空指针)

 

2.2  多做之过

 

2.2.1       由于存在fall through,switch语句会带来麻烦

 

        default可以出现在case列表的任何位置,习惯放最后。

         

        switch存在一些问题,其中之一就是它对case可能出现的值太过于放纵了。例如:可在switch的左花括号之后声明一些变量,从而进行一些局部存储的分配。

 

        需要一些临时变量吗?把它放在块地开始处!

 

        switch的另一个问题是它内部的任何语句都可以加上标签,并在执行时跳转到那里,就有可能破坏程序流的结构化。

 

        由于在C语言中,const关键字并不真正表示常量,如:

        const int two = 2;

        switch (i) {

            case 1: printf(“case 1\n”);

            case two: printf(“case 2\n”);//error: integral constant expression expected

            default: ;

        }

        这并不是switch语句本身的过错,但这条switch语句展示了const其实并不是真正的常量。

 

        也许switch语句最大的缺点是它不会在每个case标签后面的语句执行完毕后自动中止。一旦执行某个case语句,程序将会依次执行后面所有的case,除非遇到break语句。

        switch(line){

        ……

        case thing2:

            if ( x == STUFF){

                do_first_stuff();

                if ( y == OTHER_STUFF)

                    break;

                do_later_stuff();

            }//代码的意图是跳到这里……

            initialize_modes_pointer();

            break;

        default:  ;

        }//但事实上跳到了这里

        use_modes_pointer();//致使modes_pointer未初始化

        希望从if语句跳出,但却忘了break语句跳出的是最近的那层循环或者switch语句。

 

2.2.2       粉笔也成了可用的硬件

 

        ANSI C 引入的另一个新特性是相邻的字符串常量将被自动合成一个字符串的约定。这就省掉了过去在书写多行信息时必须在行末加“\”的做法,后续的字符串可以出现于每行的开头。

        旧风格:

       

        现在可以用一连串项链的字符串常量来代替它,它们会在编译时自动合并。除了最后一个字符串外,其余每个字符串末尾的‘\0’字符会被自动删除。

        新风格:

       

        然而,这种自动合并意味着字符串数组在初始化时,如果不小心漏掉了一个逗号,编译器将不会发出错误信息,而是悄无声息地把两个字符串合并在一起。

 

2.2.3       太多的缺省可见性

 

        定义C函数时,在缺省情况下函数的名字是全局可见的。可以在函数名字前加个冗余的extern关键字,也可以不加,效果是一样的。这个函数对于链接到它所在的目标文件的任何东西都是可见的。如果想限制对这个函数的房屋,就必须加个static关键字。

        function apple() { //在任何地方均可见}

        extern function pear(){ //在任何地方均可见}

        static function turnip(){//在这个文件之外不可见}

 

2.3        误做之过

 

2.3.1         骆驼背上的重载

 

        许多符号是被“重载”的——在不同的上下文环境里有不同的意义。

       

 

        当sizeof的操作数是个类型名时,两边需要加上括号,但是操作数如果是变量则不必加括号。

 

2.3.2         “有些运算的优先级是错的”

 

 

        牢记两个优先级就够了:乘法和除法先于加法和减法,在涉及其他的操作符时一律加上括号。

 

2.3.3         早期的gets()中的Bug导致了Internet蠕虫

 

2.4        少做之过

 

2.4.1         用户名中若有字符f,便不能收到邮件

2.4.2         空格——最后的领域

2.4.3         C++的另一种注释形式

2.4.4         编译器日期被破坏

 

        当包含自动变量的函数或代码块退出时,它们所占用的内存便被回收,它们的内容肯定会被下一个所调用的函数覆盖。

        解决方案

  1.        
  2. 返回一个纸箱字符串常量的指针
  3.        
  4. 使用全局声明的数组
  5.        
  6. 使用静态数组
  7.        
  8. 显示分配一些内存,保存返回的值
  9.        
  10. 也许最好的解决方案就是要求调用者分配内存来保存函数的返回值。

 

2.4.5         lint 程序绝不应该被分离出来

 

        有一项工作在lint程序中经常进行,但在当前绝大多数的C编译器中并不进行。这就是检查各个文件中函数使用的一致性。

 

2.5        轻松一下——有些特性确实是Bug

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值