- 首先看第一个问题:
char a = 10;
int b = (int)a;
这是C语言中很基础的强制转换用法:把原本为char 型的变量a强制转换为int类型。
众所周知,这样的语法是正确的,编译过程运行过程不会发生错误,但下面这种强制转换呢?
int a = 10;
char b = (char)a;
这种操作就值得商榷了,因为系统很可能因为这个语句而导致不可预料的错误,将会给项目带来不可预知的灾难。
首先这种语法有错吗?会编译不过吗?
首先,编译器对于这种操作不会提示错误,毕竟根据语法,也没什么不对的地方嘛,有时还能正确输出,比如这次:
但是有时候就不是那么幸运了,比如这样:
int a = 1000;
char b = (char)a;
看看结果:
怎么就成这个了呢?我明明a是1000啊!这个问题应该从内存上解释:
首先char 占1个字节(8位),而int 占4字节(32位)。当int被强制转换 成char的时候,int的低8位就给了char,但是呢,int其他24位怎么办呢?给谁呢?答案是丢失了,在这种“大内存”转”小内存“的强制转换中丢失了,也就是所谓的“精度丢失”。我们可以通过上述例子来验证以上理论的正确性。
首先unsigned int a = 1000化作2进制就是: 00000000 00000000 00000011 11101000
当把a转化为unsigned char 时,只有a就只有把低八位:11101000保留下来了,其余24位全部丢失,用计算机一算:11101000的十进制表示就是232。
所以小结一下: - “大内存类型”强制转换为“小内存类型”存在精度丢失的问题,也就是说,经过这种转换会导致转换后的值就不是你想要的那个值了,所以这种做法要摒弃!
- ”小内存类型“强制转换为“大内存类型“则很安全,不会发生精度丢失,只是浪费内存而已。
- 刚刚说了int和char的强制转换的原理,那么我们来讲深入的:结构体的强制转换。
结构体的强制转换在网络编程中经常遇见,所以非常有必要把这个知识点弄清楚。
typedef struct monkey{int age;int leg;int hand;char name;}monkey;
typedef struct fish{int age;char name;}fish;
typedef struct bird{int age;int wind;char name;}bird;
typedef struct animal{int head;int heart;union{bird bird_1;fish fish_1;monkey monkey_1;}u;}animal;
typedef struct test{int head;int heart;fish fish_1;}test;
首先我定义了上面五个结构体:monkey,fish,bird,animal,test。animal结构体比较特殊,它包含了一个联合体,联合体内含有monkey,fish,bird三个结构体。而test结构体的结构与animal结构类似,只是少了animal内的联合体而已。好的,对于联合体的用法我就不在这里展开了,因为大家对此比较熟悉,那么我们赶紧开始结构体的强制赋值操作。
按照int,char强制转换的例子,我们先尝试“小内存类型”强制转换成“大内存类型”的情况。
在这次的例子里,“大内存类型”为animal,“小内存类型”为test。
执行结果:
在该例子中,在调用fun函数时,example结构体被强制转换为animal结构体,从内存方面分析可以知道,animal的类型大小是>={fish,bird,monkey,example}的。所以当example被强制转换为animal时,example的数据是不会发生丢失的(也就是所谓的精度丢失)。
在执行本次操作的时候,我脑子里冒出了一个奇怪的念头:我在fun函数里加入一句: a->u.monkey_1.leg = 22;会怎么样呢?要知道,我们传入的结构体里所使用的union是fish啊!我们这样强行使用monkey作为联合体会不会不太好啊?那咱们试一试!
输出:
我们分析一下这个现象:首先编译时没有任何错误和警告的,但是输出结构就有点奇怪了: example.fish_1.name的值被修改为22!也就是说a->u.monkey_1.leg = 22一句把example.fish_1.name的值修改了!我们在函数里修改的值是monkey_1.leg啊,怎么会这样子?
从内存上分析很简单:a->u.monkey_1.leg 是对应着example.fish_1.name:
test:
animal:headheartagename
显然,test的name刚好对应animal的leg,所以值被覆盖了。headheartage
leghandname
现在考虑“大内存类型”强制转换“小内存类型”。
我们首先定义了animal 的结构体example,还有注意函数形参实参的改动。
输出结果:
没有错误。这个实验从侧面可以看出,原来定义animal example所开辟的空间暂时没有被回收,而是继续保留,所以hand,name的值还是那些。
- 总结
经过以上实验,可以明确知道的是,“小内存类型”强制转换成“大内存类型”是没任何问题的。而“小内存类型”转换为“大内存类型”就可能发生错误了。
C语言下强制转换的深度分析
最新推荐文章于 2024-01-22 21:01:22 发布