第七章

第七章

  • 有符号整数溢出,程序行为是未定义的

  • 无符号整数运算过程中发生溢出,结果是有定义的:对2^n取模,n适用于存储结果的位数

  • C标准未说明char类型是有符号还是无符号型

  • 「惯用法」

    • while(getchar()!='\n');//skip rest of line
    • while((c=getchar())==' ');//skip blanks
  • C89算术类型

    • 整值类型
      • 字符类型 char
      • 有符号整型 signed charshort intintlong int
      • 无符号整型 unsigned charunsigned shortunsigned intunsigned long
      • 枚举类型
    • 浮点类型 floatdoublelong double
  • C99算术类型

    • 整数类型
      • 字符类型 char
      • 有符号整型 包括标准的(signed charshort intintlong intlong long int)和扩展的
      • 无符号整型 包括标准的( unsigned charunsigned short intunsigned intunsigned long intunsigned long long int_Bool)和扩展的
      • 枚举类型
    • 浮点类型
      • 实数浮点类型 floatdoublelong double
      • 复数类型 float_Complexdouble _Complexlong double _Complex
  • 以下情况进行隐式转换

    • 当算术表达式或逻辑表达式中操作数的类型不相同时(C语言执行所谓的常用算术转换
    • 当赋值运算符的右侧表达式类型与左侧变量的类型不匹配时
    • 当函数调用的实参类型与形参类型不匹配时
    • 当return语句中表达式的类型与函数返回值的类型不匹配时
  • 常用算术转换

    • 整值提升(integral promotion)把字符或短整型转换成int类型(如果int类型整数没有大到足以包含所有可能的原始类型值,那么是unsigned int

    • 任一操作数是浮点类型的情况。float->double->long double

    • 两个操作数均不是浮点类型。首先进行整值提升(保证没有一个操作数是字符类型或者短整型),然后int-> unsigned int-> long int-> unsigned long int。有一种特殊情况,在unsigned intlong int相同时,如果一个操作数是unsigned int,另一个是 long int,那么都被转换为unsigned long int

    • 当把有符号操作数和无符号操作数组合时,把有符号操作数“转换”成无符号的值。转换过程中需要加上或者减去n+1的倍数,n是无符号类型能表示的最大值。这条规则会导致一些隐蔽的编程错误。例:

      #include 
      int main(int argc, char **argv){
          unsigned int a=10;
          int b = -10;
      
          printf("yes, i am %d\n", b < a);
          printf("yes, i am %d\n", -10 < 10);
          return 0;
      }
      

      运行结果是:

      yes, i am 0
      yes, i am 1
      

      结论就是:尽量避免使用无符号整数!

  • 赋值过程中的转换

    • 常用算术转换不适用于赋值运算。C语言遵循另一条简单的转换规则,那就是把赋值运算符右侧的表达式转换为左侧变量的类型
    • 如果变量类型至少和表达式类型一样宽,那么转换没有任何障碍
    • 其他情况是有问题的。把浮点数赋值给整型丢掉小数部分。把某种类型的值赋给类型更狭小的变量时,如果该值在变量类型范围之外,那么会得到无意义的结果(甚至更糟)
  • C99中的隐式转换

    • 为了定义转换规则,C99允许每个整数类型具有“整数转换等级”。下面是从最高到最低的排序(这里忽略了扩展的整数类型和枚举类型)
      1. long long intunsigned long long int
      2. long intunsigned long int
      3. intunsigned int
      4. short intunsigned short int
      5. charsigned charunsigned char
      6. _Bool
    • C99用整数提升(integer promotion)取代了C89中的整值提升(integral promotion),可以将任何等级低于intunsigned int的类型转换为intunsigned int
    • 任一操作数是浮点类型的情况。只要两个操作数都不是复数类型,float->double->long double
    • 两个操作数均不是浮点类型。首先进行整数提升,如果两个操作数类型相同,过程结束。否则一次尝试以下规则,一旦遇到可应用的规则,就不再考虑其他的规则:
      1. 如果两个操作数均为有符号型或无符号型,将整数转换等级低的转换如为等级高的操作数类型
      2. 如果无符号操作数的等级高于或等于有符号操作数的等级,将有符号操作数转换为无符号操作数的类型
      3. 如果有符号操作数的类型可以表示无符号操作数类型的所有制,将无符号操作数转换为有符号操作数的类型
      4. 否则,将两个操作数都转换为与有符号操作数的类型相对应的无符号类型
  • 强制类型转换

    • 有时需要使用强制类型转换来避免溢出,例:
    long i;
    int j = 1000;
    i = j * j;//overflow may occur
    

    在有些机器上j*j的值过大,无法表示为int型,导致溢出。
    可以改为

    i = (long)j * j;

  • sizeof运算符

    • 编译器通常就能确定sizeof表达式的值,C99值变长数组不可以。

你可能感兴趣的:(第七章)