C语言类型转换知多少?

来源:互联网 发布:转行做程序员 编辑:程序博客网 时间:2024/05/17 02:12

C语言类型转换知多少?

 

学C的都知道类型转换,可是,到底哪些类型转换是安全的,那些是有危险的?虽然类型统一规划好是好的程序开发的基础。但是有些时候避免不了类型转换的时候,这时候我们需要:

1.      了解哪些类型转换有危险(危险的都是显式类型转换?)。

2.      了解那些转换会增加代码量

3.      如何通过显式的转换来减少转换次数,提高效率

 

类型转换的方式:

 

短的转长的

等长的之间

长的转短的

有符号转无符号

符号扩展到长的

负数值变含义了

存储的二进制不变

负数值变含义了

截断

无符号转有符号

值不变

大于负数范围的值变负

截断

有符号之间

值不变

N/A

截断

无符号之间

值不变

N/A

截断

 

1.      double 和整数之间的转换是直接将小数点后截掉进行转换,反之,将整数赋值给浮点数的时候,受浮点数表达能力的限制,可能会出现整数部分不完全一样的情况,这些转换都需要代码实现

2.      无论短转长,还是长转短,这些转换都需要代码实现

 

测试当中,还发现有这个现象:

short a =-100;

unsignedshort b;

 

printf("a=%d\n",a);

printf("a=0x%x\n",a);

b =a;

printf("b=%d\n",b);

printf("b=0x%x\n",b);

 

结果如下:

 

a=-100

a=0xffffff9c

b=65436

b=0xff9c

 

为什么a和b的十六进制数打印的不一样呢?我们看看真正是怎么处理的:

movw $-100,-2(%rbp)         // a = -100;

movswl    -2(%rbp),%eax     // 准备参数,因为类型是short,所以做一次隐式转换,相当于(int)a;由于是有符号数,所以符号扩展了。

movl %eax,%esi

movl $.LC0,%edi

movl $0,%eax

call printf                  // printf("a=%d\n",(int)a);

movswl    -2(%rbp),%eax

movl %eax,%esi

movl $.LC1,%edi

movl $0,%eax

call printf

movzwl    -2(%rbp),%eax     // 寄存器eax = a; 这里无论怎么扩展,下一步取得都只是低32位,所以不会有任何影响。

movw %ax,-4(%rbp)      // b = 寄存器ax(32);

movzwl    -4(%rbp),%eax     // 准备参数,因为类型是short,所以做一次隐式转换,相当于(unsigned int)a;

movl %eax,%esi

movl $.LC2,%edi

movl $0,%eax

call printf                  //printf("b=%d\n", (unsigned int)b);

movzwl    -4(%rbp),%eax

movl %eax,%esi

movl $.LC3,%edi

movl $0,%eax

call printf

 

从上面的代码可以看出,确实printf的输入参数,小于int的类型是要转换为相应的int,然后调用printf进行打印的,这也是C语言函数处理入参的默认行为。

 

隐式转换规则:

就是不需要明确指定,编译器会生成相关的代码进行转换:

 

1.      关于表达式运算

首先:不同类型数运算的时候,先要转换为相同的,转换规则是表达能力小的转换为表达能力大的,即:短的转换为长的。

 

其次:整形计算的最小单位是int,如果是小于int的数字,先要转换为int。浮点数计算的单位都是double,所以所有的参与浮点运算的任何一方只要是浮点数,大家都会转换为double进行运算。这么做的原因是:保证精度。

 

2.      关于赋值

赋值是强制按照左边的类型进行转换,有可能是显式的截断,参见上表。

 

0 0