C语言下强制转换的深度分析

  • 首先看第一个问题:
    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:                  
    head
    heart
    age
    name
    animal:
    head
    heart
    age
    leg
    hand
    name
    显然,test的name刚好对应animal的leg,所以值被覆盖了。

    现在考虑“大内存类型”强制转换“小内存类型”。

      我们首先定义了animal 的结构体example,还有注意函数形参实参的改动。
    输出结果:

    没有错误。这个实验从侧面可以看出,原来定义animal example所开辟的空间暂时没有被回收,而是继续保留,所以hand,name的值还是那些。


  • 总结
    经过以上实验,可以明确知道的是,“小内存类型”强制转换成“大内存类型”是没任何问题的。而“小内存类型”转换为“大内存类型”就可能发生错误了。











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值