C陷阱与缺陷

C陷阱与缺陷和高质量C编程这两本书主要是总结一些C编程人员常犯的一些错误,常遇到的一些语法陷阱,及不良的编程风格。无论是有多年经验的编程老手还是刚入门的新手,细细品读,都会有不少的收获和感悟。此篇博客是个人读完这两本书后的一些感悟及对一些内容的记录,方便日后翻阅。

  • 词法陷阱

    • 多个操作字符组在一起的处理方法

    编译器中负责将我们编译的命令符号进行分解的部分称为”词法分析器“,而词法分析器在工作运行时采用的处理策略为”贪心法“ 。什么意思呢?举个栗子,如这段语句a---b,编译器在运行时会识别为a-- - b而不是a - --b 也就是说编译器会先按从左到右的顺序读取一个字符,紧接着再读取第二个字符,然后判断这两个字符是否能够组成一个有实际意义的操作符,如果能组成,那么编译器还会读取第三个字符(如果存在第三的话)然后再进行同样的判断,直到读取的字符与前面所读取的字符的组合没有实际的意义了。我们再把视角拉回到a---b中,编译器会先读取” - “这个操作符,然后再读取一个” - “操作符,发现能够组成” -- “这个有实际意义的操作符,接着编译器再读取第三个” - “操作符,然后发现三个” - “操作符组成的字符没有实际意义,因此将” --- “拆分成了” -- “和” - “,最终语句的效果就是a-- - b ,这里需要注意的是,这是编译器在面临多个操作字符组在一起的处理办法。

    • 操作符之间的空格与括号的合理应用

      各个操作符之间的空格要根据想表达的意思谨慎添加,比如想表达是否等于的判断,应该写成==,而不是= =,= =这样的格式,严格的编译器是直接报错的。如 m = n/*p 这段语句的本意是n除以p指向的内容,然后把值赋给m,但编译器会将 /* 解读成注释的前半部分,不会再管后面的内容,如果写成m = n / *p 或者m = n / (*p)就能表达出想要表达的意思。

      不同的编译器采用的操作符的处理办法不尽相同,所以我们在编写程序时该加空格就加空格,该加括号就加括号,尽量把意思表达清楚,避免写出会产生歧义的代码,别舍不得用括号,不为难编译器,也不要为难自己。

    • 整型数字运算需要注意的

      整型数字在运算时,避免为了使数字对齐美观而在数字面前加上 0 ,这样的话,编译器会将这串十进制数字识别为八进制数字,如果不知道这种情况,会导致得不到想要的结果而苦恼

      //例如
      int a = 123;
      int b = 034;  //这里编译器会把34当作八进制数字来处理

      如果在进行整数除法运算,且想得到具体的结果时,最好将其转化成浮点型,使用强制类型转换,或在某个数字后面加上" .0 "编译器会自动将其转换成浮点型

          
          float c = 0.0f;
          c = 1 / 4;
          printf("%f", c);//不可,c的结果为0.000000
      ​
          float c = 0.0f;
          c = (float)1 / 4;
          printf("%f", c);//可,c结果为0.250000
      ​
          float c = 0.0f;
          c = 1.0 / 4;
          printf("%f", c);//可,c结果为0.250000

      char类型本质上是属于整型家族的,其在运算时,需要进行整形提升,为什么进行整型提升呢?

      表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度 一般就是int的字节长度,同时也是CPU的通用寄存器的长度。 因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长 度。 通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令 中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转 换为int或unsigned int,然后才能送入CPU去执行运算。

      在存储时要进行截断,因为char只能存放8个二进制数

    • 字符与字符串的区别

      由单引号引起的字符,本质上代表着一个整数,该整数值对应着编译器采用的字符集所对应的字符的序列值。由双引号引起的字符串,本质上是一个指针,指向一个无名数组起始字符的指针,该数组被双引号之间的字符以及\0所初始化。

      避免在单引号的字符里放入多个字符,因为不同编译器的处理规则是不同的,有的取第一个字符,有的取最后一个字符,所产生的结果都是不确定的。也不要将单引号引起的字符赋值给char 类型的指针,这样是不行的,因为它的本质就是一个整数,但有的编译器不会报错的,这需要我们多加留意了。

      char *p = 'a'; //这样不行,'a'不是一个指针;
      //由于printf()函数的一些特性,采用不确定参数,原型为 int printf(const char *format[argument]...)
      //导致一些编译器对该函数的参数的检查并不是很严格
      //这就容易导致一个问题
      printf('\n'),这种写法可能不会报错,这会导致难以预料的结果

  • 良好的编程习惯

    为了避免产生一些不必要的错误,我们可以从编程习惯上逐步改善

    int a = 3;
    if ( a == 3 )     不妨将其写成if (3 == a)
    {                 3是无法被赋值的,如果少些一个 = 编译器会报错的
     ......
    }
    ​
    //关键字与括号的接触中间最好有一个空格,以表明和函数的区别
    if()      //建议写成if ()
    while()   建议写成while ()  
     
    //函数是紧贴括号的
        printf()
        scanf()
       // 不过现在一些高级的编译器会自动加空格的,还是很方便的;
        
     //函数在声明和定义时,最好将变量名补全 。
      void fun(int; int)//不好的风格
      void fun(int x, int y)//良好的风格
        
        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪雨123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值