深入理解C语言类型转换

来源:互联网 发布:天刀怎么保存捏脸数据 编辑:程序博客网 时间:2024/04/29 10:41

类型转换简要介绍


C语言类型转换分为两种:

  • 显式强制类型转换

  • 隐式自动类型转换

也许你曾经遇到过一个负数经过类型转换后可能变成一个很大的整数之类的现象,却不知道实质上是因为什么,只是浅显地了解到类型转换会向着更大精度的方向转化。尤其是对于计算机基础知识不扎实或者很多半路出家(比如我)的人来说不是很了解背后的原因。希望下面的解释能够解决这个疑惑。本文以C语言为例,其他类似语言也有类似的结论,深究到底自会明白。

下面从详细介绍一个显式类型转换开始。要想深入理解类型转换,首先要有机器数(原码、补码和反码)的相关基本了解。我们都知道在计算机中信息都以二进制用0和1来表示信息。为了运算方便,大多采用补码形式存储数据。比如一个C语言的short类型,一般short类型为2个字节,也就是用16位二进制数表示。那么在计算机中的-1(也就是所谓的真值)表示为,也就是16位的-1补码为:

[1]=1111111111111111

简单测试一下计算机中是否以补码表示运算数据:

将10进制转换成为二进制函数:

/*  模板函数,可将基本数据类型的10进制表示(说法欠妥,您能理解就行)转换成计算机中的二进制表示  */template<class T>char* DecimalToBinary(T n, char *b){    const int length = 8 * sizeof(T);    for (int i = length - 1; i >= 0; i--, n >>= 1)        b[i] = (1 & n) + '0';  //  1与n进行位运算将得到n的最后一位二进制表示    b[length] = '\0';    return b;}

测试代码:

void main(){    short a = -1;    char *b = new char[sizeof(a)*8];    cout << "10进制:  " << a << endl;    cout << "二进制:  " << DecimalToBinary(a, b) << endl;    return;}

运行结果:

运行结果

如我们预期, 真值 -1 在计算机中的16位机器数表示为1111 1111 1111 1111。

计算机如何处理类型转换

理解的前提有了,下面进入正题:计算机如何处理类型转换。


先来看一下同等长度变量是如何处理的。

同等长度变量之间的类型转换

同样长度的不同类型相互转换时,比方 short 强制转换成 unsigned short。实际在转换过程中,转换后的 unsigned short 与原来的 short 在计算机中的二进制表示形式一样的,改变的只不过是解释他们的方式。

强制类型转换结果保持位值不变,只是改变了解释这些位的方式。

代码测试:
void main(){    short a = -4321;    unsigned short ua = (unsigned short)a;  //  这里进行强制类型转换    char *b = new char[sizeof(a)*8];    cout << "sizeof(short):           " << sizeof(short) << endl;    cout << "sizeof(unsigned short):  " << sizeof(unsigned short) << endl;    cout << "真值:" << setw(32) << a << " 机器数" << DecimalToBinary(a, b) << endl;    cout << "真值:" << setw(32) << ua << " 机器数" << DecimalToBinary(ua, b) << endl;    return;}

运行结果:

运行结果

结果分析:

显然,结果如预期。可以试一下,按照无符号数的解释,1110111100011111这么一串补码的确表示61215。

不同长度变量之间的类型转换

上面介绍了理解类型转换的前提。并详细介绍了同等长度(比方 int 类型与 unsigned int类型一般都是2个字节的表示长度)的不同类型转换,并且总结一句话就是:

强制类型转换结果保持位值不变,只是改变了解释这些位的方式。


下面来看一下不同字长变量之间的转换:

  • 长字长变量向短字长变量的转换

    • 处理方式:
      系统把多余的高位字长部分直接截断,低位直接赋值,也是一种保持位值的处理方法。

    • 将10进制数转换成二进制在上一篇提供了方法。

    • 测试代码:

      void main(){int x = -4321;char *bx = new char[sizeof(x)* 8];short y = x;char *by = new char[sizeof(y)* 8];cout << "真值:" << x << setw(20)<< " 机器数: " << DecimalToBinary(x, bx) << endl;cout << "真值:" << y<< setw(20) << " 机器数: " << DecimalToBinary(y, by) << endl;return;}
    • 运行结果
      运行结果

    • 结果分析
      高位截断,低位直接赋值,如预期。
  • 短字长变量向长字长变量的转换

    • 处理方式:
      短字长转向长字长,不仅是相应的位值相等,高位部分还会扩展为原数字的符号位。

    • 测试代码:

      void main(){short x = -4321;char *bx = new char[sizeof(x)* 8];int y = x;char *by = new char[sizeof(y)* 8];cout << "真值:" << x << setw(20)<< " 机器数: " << DecimalToBinary(x, bx) << endl;cout << "真值:" << y<< setw(20) << " 机器数: " << DecimalToBinary(y, by) << endl;cout << endl;x = 4321;y = x;cout << "真值:" << x << setw(21) << " 机器数: " << DecimalToBinary(x, bx) << endl;cout << "真值:" << y << setw(21) << " 机器数: " << DecimalToBinary(y, by) << endl;return;}
    • 运行结果:
      运行结果

    • 结果分析
      低位位值对应相等,高位扩展为短字长的符号位,如预期。

类型转换总结


相信大家已经对于类型转换有了较为深刻的认识。终究要理解本质的话,还是要深入到0/1的世界,站在计算机的角度理解我们看到的表面现象。

上面提到的知识,其实在大学里面开设的计算机组成原理这门课都有。另外推荐一本书《深入理解计算机系统》,最新版本是第三版不过时英文,现在网上流传的应该还是第二版,本文内容即可在书中找到对应。

就像学的很多数学,微积分、线性代数、概率论,一开始并不知道学这么些有什么用,卖菜的大爷大妈不会调皮到要出个题目才把菜卖给你,玩骰子的时候也不会想着算计它出现某个数字的概率。不过后来在接触机器学习与数据挖掘的过程中,才能够慢慢发现数学的用处。如果能够在当初开始学习的时候就能够感受到这些,那该有多好。


测试代码注意:

    - 如果自己写程序测试以上理论的话,请注意相关细节。    二进制表示如果采用数组存储的话,记得在10进制数对应所需的二进制数上加1。否则会溢出。    而这种溢出经试验在VC6.0下面并不会被检查出来,程序可以运行,但是最终结果将不会是预期。    - 在VS下面就能够检测出这种错误并终止程序运行,故建议使用VS. 否则可能由于一些其他外在原因(编译器的原因)将得不到理论值。
0 0
原创粉丝点击