zoukankan      html  css  js  c++  java
  • C++中关于类型转换的问题讨论

    这里以signed/unsigned char, signed/unsigned short, signed/unsigned int类型为例,

    讨论一下基本类型转换的基本原理,这样我们在编程中碰到由类型错误转换而引发的越界问题时,也可以比较容易诊断,不至于把BUG怀疑到机器或编译器身上:)。

    本文属于个人原创,任何个人都可以转载,但请务必提供转载地址。

    一,3种基本类型表示范围如下 (圆形示例图),其中阴影部分的弧边界包含的是没有越界的数值范围:

    2,类型转换原则小结:

    我们把类型转换分成两类:

    1)同类型符号之间的转换:

      *同长度类型,不做转换,如int->int,

      *向更长度类型转换,如char->short->int

      原则:向高字节对齐

           因为有足够位数容纳数值,所以数值会保持不变;

         若为负数时高位会被1,若为正数时高位会补0.

          *向短长度类型转换:如int ->short->char

           原则:高字节截断,低字节保留。

    2)不同类型符号之间的转换:

      *同长度类型转换:如int<->unsigned int

      原则:重新解释至目标类型,

          这里是重新解释,换名话说,在等长字节时,有符号类型和无符号类型在内存中的十六进制表示仍然是一样的。

         当数值范围溢出时,重新解释会造成前后两者数值的会发生巨大跳变,详见示例。

      *向更长类型转换:如char->unsigned int

      原则:先字节对齐,再类型统一。

         如:char->unsigned int  ===>char -> int ->unsigned int

                      unsigned char -> int ===>unsigned char ->unsigned int ->int

      这个原则会造成将负数执行”跨类型跨字节“转换时,前后两数值之间很大差距,

      如果想让差距变得”相对“合理些(等价于重新解释后的数值),你需要手动做强制转换:先类型统一,再做字节对齐。

      *向更短字节对齐:如int->unsigned char

      原则:高字节截断,低字节保留

    提示:

      1)如果想要转换无错,还是规规矩矩的保证数值:不要溢出,不要截断,不要跨类型跨字节转换。

      2)在”有符号类型“向”无符号类型“转换时,数值不要为负数,否则打印出的数值并非你想要的结果。

      尤其是“有符号短字节类型“向”无符号长字节类型转换“时,负数会按照高字节补1的原则,你将会得到一个无敌错错值。

    3,类型转换源代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
    
    typedef char s8;
    typedef unsigned u8;
    typedef short s16;
    typedef unsigned short u16;
    typedef int s32;
    typedef unsigned int u32;
    
    #define NONE "33[0m"
    #define BLUE "33[0;32m"
    #define RED "33[0;31m"
    
    void func_s8(s8 num)
    {
        s8 s8Num     = num;
        u8 u8Num     = num;
        s16 s16Num     = num;
        u16 u16Num     = num;
        s32 s32Num     = num;
        u32 u32Num     = num;
        //signed->signed
        printf(BLUE " s8[%hhd#0x%02hhx]:" NONE "
    s16(%hd#0x%04hx) 
    s32(%d#0x%08x)
    ", 
            s8Num, s8Num, s16Num, s16Num, s32Num, s32Num);
    
        //signed->unsigned 
        printf(" u8(%hhu#0x%02hhx) 
    u16(%hu#0x%04hx) 
    u32(%u#0x%08x)
    ",
            u8Num, u8Num, u16Num, u16Num, u32Num, u32Num);
    }
    
    void func_u8(u8 num)
    {
        s8 s8Num     = num;
        u8 u8Num     = num;
        s16 s16Num     = num;
        u16 u16Num     = num;
        s32 s32Num     = num;
        u32 u32Num     = num;
        //unsigned->unsigned
        printf(BLUE " u8[%hhu#0x%02hhx)]" NONE "
    u16(%hu#0x%04hx) 
    u32(%u#0x%08x)
    ",
            u8Num, u8Num, u16Num, u16Num, u32Num, u32Num);
    
        //unsigned->signed 
        printf(" s8(%hhd#0x%02hhx): 
    s16(%hd#0x%04hx) 
    s32(%d#0x%08x)
    ", 
            s8Num, s8Num, s16Num, s16Num, s32Num, s32Num);
    }
    
    void func_s16(s16 num)
    {
        s8 s8Num     = num;
        u8 u8Num     = num;
        s16 s16Num     = num;
        u16 u16Num     = num;
        s32 s32Num     = num;
        u32 u32Num     = num;
        //signed->signed
        printf(BLUE "s16[%hd#0x%04hx]: " NONE "
    s32(%d#0x%08x) 
     s8(%hhd#0x%02hhx)
    ", 
            s16Num, s16Num, s32Num, s32Num, s8Num, s8Num);
    
        //signed->unsigned 
        printf("u16(%hu#0x%04hx) 
    u32(%u#0x%08x) 
     u8(%hhu#0x%02hhx)
    ",
            u16Num, u16Num, u32Num, u32Num, u8Num, u8Num);
    }
    
    void func_u16(u16 num)
    {
        s8 s8Num     = num;
        u8 u8Num     = num;
        s16 s16Num     = num;
        u16 u16Num     = num;
        s32 s32Num     = num;
        u32 u32Num     = num;
        //unsigned->unsigned
        printf(BLUE "u16[%hu#0x%04hx]:" NONE "
    u32(%u#0x%08x) 
     u8(%hhu#0x%02hhx)
    ",
            u16Num, u16Num, u32Num, u32Num, u8Num, u8Num);
    
        //unsigned->signed 
        printf("s16(%hd#0x%04hx) 
    s32(%d#0x%08x) 
     s8(%hhd#0x%02hhx)
    ", 
            s16Num, s16Num, s32Num, s32Num, s8Num, s8Num);
    }
    
    void func_s32(s32 num)
    {
        s8 s8Num     = num;
        u8 u8Num     = num;
        s16 s16Num     = num;
        u16 u16Num     = num;
        s32 s32Num     = num;
        u32 u32Num     = num;
        //signed->signed
        printf(BLUE "s32[%d#0x%08x]:" NONE "
    s16(%hd#0x%04hx) 
     s8(%hhd#0x%02hhx)
    ", 
            s32Num, s32Num, s16Num, s16Num, s8Num, s8Num);
    
        //signed->unsigned 
        printf("u32(%u#0x%08x) 
    u16(%hu#0x%04hx) 
     u8(%hhu#0x%02hhx)
    ",
            u32Num, u32Num, u16Num, u16Num, u8Num, u8Num);
    }
    
    void func_u32(u32 num)
    {
        s8 s8Num     = num;
        u8 u8Num     = num;
        s16 s16Num     = num;
        u16 u16Num     = num;
        s32 s32Num     = num;
        u32 u32Num     = num;
        //unsigned->unsigned
        printf(BLUE "u32[%u#0x%08x]" NONE "
    u16(%hu#0x%04hx) 
     u8(%hhu#0x%02hhx)
    ",
            u32Num, u32Num, u16Num, u16Num, u8Num, u8Num);
    
        //unsigned->signed 
        printf("s32(%d#0x%08x): 
    s16(%hd#0x%04hx) 
     s8(%hhd#0x%02hhx)
    ", 
            s32Num, s32Num, s16Num, s16Num, s8Num, s8Num);
    }
    
    int main()
    {
        printf(RED "######s8Num testing######
    " NONE);
        s8 s8Num = 0x7F;
        func_s8(s8Num);
        s8Num = 0x80;
        func_s8(s8Num);
        s8Num = 0xFF;
        func_s8(s8Num);
        
        printf(RED "######u8Num testing######
    "NONE);
        u8 u8Num = 0x7F;
        func_u8(u8Num);
        u8Num = 0x80;
        func_u8(u8Num);
        u8Num = 0xFF;
        func_u8(u8Num);
    
        printf(RED "######s32Num testing######
    "NONE);
        s32 s32Num = 0x7FFFFFFF;
        func_s32(s32Num);
        s32Num = 0x80000000;
        func_s32(s32Num);
        s32Num = 0xFFFFFFFF;
        func_s32(s32Num);
        
        printf(RED "######u32Num testing######
    "NONE);
        u32 u32Num = 0x7FFFFFFF;
        func_u32(u32Num);
        u32Num = 0x80000000;
        func_u32(u32Num);
        u32Num = 0xFFFFFFFF;
        func_u32(u32Num);
        
        printf(RED "######s16Num testing######
    "NONE);
        s16 s16Num = 0x7FFF;
        func_s16(s16Num);
        s16Num = 0x8000;
        func_s16(s16Num);
        s16Num = 0xFFFF;
        func_s16(s16Num);
        
        printf(RED "######u16Num testing######
    "NONE);
        u16 u16Num = 0x7FFF;
        func_u16(u16Num);
        u16Num = 0x8000;
        func_u16(u16Num);
        u16Num = 0xFFFF;
        func_u16(u16Num);
        
        return 0;
    }

    4,类型转换运行结果

    ######s8Num testing######
     s8[127#0x7f]:
    s16(127#0x007f) 
    s32(127#0x0000007f)
     u8(127#0x7f) 
    u16(127#0x007f) 
    u32(127#0x0000007f)
     s8[-128#0x80]:
    s16(-128#0xff80) 
    s32(-128#0xffffff80)
     u8(128#0x80) 
    u16(65408#0xff80) 
    u32(4294967168#0xffffff80)
     s8[-1#0xff]:
    s16(-1#0xffff) 
    s32(-1#0xffffffff)
     u8(255#0xff) 
    u16(65535#0xffff) 
    u32(4294967295#0xffffffff)
    ######u8Num testing######
     u8[127#0x7f)]
    u16(127#0x007f) 
    u32(127#0x0000007f)
     s8(127#0x7f): 
    s16(127#0x007f) 
    s32(127#0x0000007f)
     u8[128#0x80)]
    u16(128#0x0080) 
    u32(128#0x00000080)
     s8(-128#0x80): 
    s16(128#0x0080) 
    s32(128#0x00000080)
     u8[255#0xff)]
    u16(255#0x00ff) 
    u32(255#0x000000ff)
     s8(-1#0xff): 
    s16(255#0x00ff) 
    s32(255#0x000000ff)
    ######s32Num testing######
    s32[2147483647#0x7fffffff]:
    s16(-1#0xffff) 
     s8(-1#0xff)
    u32(2147483647#0x7fffffff) 
    u16(65535#0xffff) 
     u8(255#0xff)
    s32[-2147483648#0x80000000]:
    s16(0#0x0000) 
     s8(0#0x00)
    u32(2147483648#0x80000000) 
    u16(0#0x0000) 
     u8(0#0x00)
    s32[-1#0xffffffff]:
    s16(-1#0xffff) 
     s8(-1#0xff)
    u32(4294967295#0xffffffff) 
    u16(65535#0xffff) 
     u8(255#0xff)
    ######u32Num testing######
    u32[2147483647#0x7fffffff]
    u16(65535#0xffff) 
     u8(255#0xff)
    s32(2147483647#0x7fffffff): 
    s16(-1#0xffff) 
     s8(-1#0xff)
    u32[2147483648#0x80000000]
    u16(0#0x0000) 
     u8(0#0x00)
    s32(-2147483648#0x80000000): 
    s16(0#0x0000) 
     s8(0#0x00)
    u32[4294967295#0xffffffff]
    u16(65535#0xffff) 
     u8(255#0xff)
    s32(-1#0xffffffff): 
    s16(-1#0xffff) 
     s8(-1#0xff)
    ######s16Num testing######
    s16[32767#0x7fff]: 
    s32(32767#0x00007fff) 
     s8(-1#0xff)
    u16(32767#0x7fff) 
    u32(32767#0x00007fff) 
     u8(255#0xff)
    s16[-32768#0x8000]: 
    s32(-32768#0xffff8000) 
     s8(0#0x00)
    u16(32768#0x8000) 
    u32(4294934528#0xffff8000) 
     u8(0#0x00)
    s16[-1#0xffff]: 
    s32(-1#0xffffffff) 
     s8(-1#0xff)
    u16(65535#0xffff) 
    u32(4294967295#0xffffffff) 
     u8(255#0xff)
    ######u16Num testing######
    u16[32767#0x7fff]:
    u32(32767#0x00007fff) 
     u8(255#0xff)
    s16(32767#0x7fff) 
    s32(32767#0x00007fff) 
     s8(-1#0xff)
    u16[32768#0x8000]:
    u32(32768#0x00008000) 
     u8(0#0x00)
    s16(-32768#0x8000) 
    s32(32768#0x00008000) 
     s8(0#0x00)
    u16[65535#0xffff]:
    u32(65535#0x0000ffff) 
     u8(255#0xff)
    s16(-1#0xffff) 
    s32(65535#0x0000ffff) 
     s8(-1#0xff)
  • 相关阅读:
    一步一步学grails:7 MVC
    虚拟机安装CentOS7
    虚拟机安装windows sever2008
    微信console
    centOS7常用操作命令
    lr事务
    2.0通信之调用ADO.NET Data Services(数据服务)
    Silverlight应用程序中如何获取ASP.NET页面参数
    2.0网页之可脚本化, 与DOM的交互, 与JavaScript的交互
    2.0Tip/Trick之MessageBox, Popup, 循环的几种实现方法, 动态变换主题, 本地化(多语言), 响应鼠标双击事件
  • 原文地址:https://www.cnblogs.com/jacklikedogs/p/4137376.html
Copyright © 2011-2022 走看看