这里以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 "\033[0m"
#define BLUE "\033[0;32m"
#define RED "\033[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 "\ns16(%hd#0x%04hx) \ns32(%d#0x%08x)\n",
s8Num, s8Num, s16Num, s16Num, s32Num, s32Num); //signed->unsigned
printf(" u8(%hhu#0x%02hhx) \nu16(%hu#0x%04hx) \nu32(%u#0x%08x)\n",
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 "\nu16(%hu#0x%04hx) \nu32(%u#0x%08x)\n",
u8Num, u8Num, u16Num, u16Num, u32Num, u32Num); //unsigned->signed
printf(" s8(%hhd#0x%02hhx): \ns16(%hd#0x%04hx) \ns32(%d#0x%08x)\n",
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 "\ns32(%d#0x%08x) \n s8(%hhd#0x%02hhx)\n",
s16Num, s16Num, s32Num, s32Num, s8Num, s8Num); //signed->unsigned
printf("u16(%hu#0x%04hx) \nu32(%u#0x%08x) \n u8(%hhu#0x%02hhx)\n",
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 "\nu32(%u#0x%08x) \n u8(%hhu#0x%02hhx)\n",
u16Num, u16Num, u32Num, u32Num, u8Num, u8Num); //unsigned->signed
printf("s16(%hd#0x%04hx) \ns32(%d#0x%08x) \n s8(%hhd#0x%02hhx)\n",
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 "\ns16(%hd#0x%04hx) \n s8(%hhd#0x%02hhx)\n",
s32Num, s32Num, s16Num, s16Num, s8Num, s8Num); //signed->unsigned
printf("u32(%u#0x%08x) \nu16(%hu#0x%04hx) \n u8(%hhu#0x%02hhx)\n",
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 "\nu16(%hu#0x%04hx) \n u8(%hhu#0x%02hhx)\n",
u32Num, u32Num, u16Num, u16Num, u8Num, u8Num); //unsigned->signed
printf("s32(%d#0x%08x): \ns16(%hd#0x%04hx) \n s8(%hhd#0x%02hhx)\n",
s32Num, s32Num, s16Num, s16Num, s8Num, s8Num);
} int main()
{
printf(RED "######s8Num testing######\n" NONE);
s8 s8Num = 0x7F;
func_s8(s8Num);
s8Num = 0x80;
func_s8(s8Num);
s8Num = 0xFF;
func_s8(s8Num); printf(RED "######u8Num testing######\n"NONE);
u8 u8Num = 0x7F;
func_u8(u8Num);
u8Num = 0x80;
func_u8(u8Num);
u8Num = 0xFF;
func_u8(u8Num); printf(RED "######s32Num testing######\n"NONE);
s32 s32Num = 0x7FFFFFFF;
func_s32(s32Num);
s32Num = 0x80000000;
func_s32(s32Num);
s32Num = 0xFFFFFFFF;
func_s32(s32Num); printf(RED "######u32Num testing######\n"NONE);
u32 u32Num = 0x7FFFFFFF;
func_u32(u32Num);
u32Num = 0x80000000;
func_u32(u32Num);
u32Num = 0xFFFFFFFF;
func_u32(u32Num); printf(RED "######s16Num testing######\n"NONE);
s16 s16Num = 0x7FFF;
func_s16(s16Num);
s16Num = 0x8000;
func_s16(s16Num);
s16Num = 0xFFFF;
func_s16(s16Num); printf(RED "######u16Num testing######\n"NONE);
u16 u16Num = 0x7FFF;
func_u16(u16Num);
u16Num = 0x8000;
func_u16(u16Num);
u16Num = 0xFFFF;
func_u16(u16Num); return ;
}

4,类型转换运行结果

######s8Num testing######
s8[127#0x7f]:
s16(#0x007f)
s32(#0x0000007f)
u8(#0x7f)
u16(#0x007f)
u32(#0x0000007f)
s8[-128#0x80]:
s16(-#0xff80)
s32(-#0xffffff80)
u8(#0x80)
u16(#0xff80)
u32(#0xffffff80)
s8[-1#0xff]:
s16(-#0xffff)
s32(-#0xffffffff)
u8(#0xff)
u16(#0xffff)
u32(#0xffffffff)
######u8Num testing######
u8[127#0x7f)]
u16(#0x007f)
u32(#0x0000007f)
s8(#0x7f):
s16(#0x007f)
s32(#0x0000007f)
u8[128#0x80)]
u16(#0x0080)
u32(#0x00000080)
s8(-#0x80):
s16(#0x0080)
s32(#0x00000080)
u8[255#0xff)]
u16(#0x00ff)
u32(#0x000000ff)
s8(-#0xff):
s16(#0x00ff)
s32(#0x000000ff)
######s32Num testing######
s32[2147483647#0x7fffffff]:
s16(-#0xffff)
s8(-#0xff)
u32(#0x7fffffff)
u16(#0xffff)
u8(#0xff)
s32[-2147483648#0x80000000]:
s16(#0x0000)
s8(#0x00)
u32(#0x80000000)
u16(#0x0000)
u8(#0x00)
s32[-1#0xffffffff]:
s16(-#0xffff)
s8(-#0xff)
u32(#0xffffffff)
u16(#0xffff)
u8(#0xff)
######u32Num testing######
u32[2147483647#0x7fffffff]
u16(#0xffff)
u8(#0xff)
s32(#0x7fffffff):
s16(-#0xffff)
s8(-#0xff)
u32[2147483648#0x80000000]
u16(#0x0000)
u8(#0x00)
s32(-#0x80000000):
s16(#0x0000)
s8(#0x00)
u32[4294967295#0xffffffff]
u16(#0xffff)
u8(#0xff)
s32(-#0xffffffff):
s16(-#0xffff)
s8(-#0xff)
######s16Num testing######
s16[32767#0x7fff]:
s32(#0x00007fff)
s8(-#0xff)
u16(#0x7fff)
u32(#0x00007fff)
u8(#0xff)
s16[-32768#0x8000]:
s32(-#0xffff8000)
s8(#0x00)
u16(#0x8000)
u32(#0xffff8000)
u8(#0x00)
s16[-1#0xffff]:
s32(-#0xffffffff)
s8(-#0xff)
u16(#0xffff)
u32(#0xffffffff)
u8(#0xff)
######u16Num testing######
u16[32767#0x7fff]:
u32(#0x00007fff)
u8(#0xff)
s16(#0x7fff)
s32(#0x00007fff)
s8(-#0xff)
u16[32768#0x8000]:
u32(#0x00008000)
u8(#0x00)
s16(-#0x8000)
s32(#0x00008000)
s8(#0x00)
u16[65535#0xffff]:
u32(#0x0000ffff)
u8(#0xff)
s16(-#0xffff)
s32(#0x0000ffff)
s8(-#0xff)

C++中关于类型转换的问题讨论的更多相关文章

  1. java中强制类型转换

    在Java中强制类型转换分为基本数据类型和引用数据类型两种,这里我们讨论的后者,也就是引用数据类型的强制类型转换. 在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需 ...

  2. JavaScript中数据类型转换总结

    JavaScript中数据类型转换总结 在js中,数据类型转换分为显式数据类型转换和隐式数据类型转换. 1, 显式数据类型转换 a:转数字: 1)Number转换: 代码: var a = " ...

  3. JS中String类型转换Date类型 并 计算时间差

    JS中String类型转换Date类型 1.比较常用的方法,但繁琐,参考如下:主要使用Date的构造方法:Date(int year , int month , int day)<script& ...

  4. SQL中的类型转换

    SQL中的类型转换一直是以块心病,因为用得比较少,所以每次想用的时候都要想半天,恰好这段时间比较空,整理整理.今天写个标题先.

  5. Struts2中的类型转换

    1.     Struts2中的类型转换 我们知道通过HTTP提交到后台的数据,都是字符串的形式,而我们需要的数据类型当然不只字符串类型一种.所以,我们需要类型转换! 在Struts2中,类型转换的概 ...

  6. java中的类型转换

    java中的类型转换分为两种 自动类型转换 要实现数据的自动类型转换必须同时满足下面两个条件 两种数据类型彼此兼容 目标类型的取值范围大于原类型范围 强制类型转换 当两种数据类型彼此不兼容,或者说目标 ...

  7. HQL语句中数据类型转换,及hibernate中createQuery执行hql报错

    一.HQL语句中数据类型转换: 我们需要从数据库中取出序号最大的记录,想到的方法就是使用order by子句进行排序(desc倒序),然后取出第一个对象,可是当初设计数据库时(我们是在原来的数据库的基 ...

  8. Java中数据类型转换&基本类型变量和对象型变量

    1.Java的数据类型分为三大类 布尔型,字符型和数值型 其中数值型又分为整型和浮点型 2.Java的变量类型 布尔型 boolean 字符型 char 整型    byte,short,int,lo ...

  9. C语言中强制类型转换总结

    C语言中强制类型转换总结  ● 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128-127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围 ...

随机推荐

  1. iOS 开发--Objective-C 反射机制

    了解反射机制 Objective-C语言中的OC对象,都继承自NSObject类.这个类为我们提供了一些基础的方法和协议,我们可以直接调用从这个类继承过来方法.当然,本篇文章中讲到的反射方法,就在NS ...

  2. iOS开发--基于AFNetWorking3.0的图片缓存分析

    图片在APP中占有重要的角色,对图片做好缓存是重要的一项工作.[TOC] 理论 不喜欢理论的可以直接跳到下面的Demo实践部分 缓存介绍 缓存按照保存位置可以分为两类:内存缓存.硬盘缓存(FMDB.C ...

  3. SPRING IN ACTION 第4版笔记-第十章Hitting the database with spring and jdbc-004-使用NamedParameterJdbcTemplate

    为了使查询数据库时,可以使用命名参数,则要用NamedParameterJdbcTemplate 1.Java文件配置 @Bean public NamedParameterJdbcTemplate ...

  4. SMB2 Protocol – 简介(应用层协议主要用于在计算机间共享文件、打印机、串口等)

    SMB2 Protocol – 简介 SMB协议简介: 服务器信息块(SMB)协议是一个应用层协议主要用于在计算机间共享文件.打印机.串口等. 在介绍SMB协议的时候,一般提到使用的端口为139,44 ...

  5. 科普:WiFi是谁申请的专利?高通吗?错!

    你给Wi-Fi交过专利费吗?你知道Wi-Fi是谁申请的专利吗? 答:肯定是高通! 错! Wi-Fi技术由澳洲政府的研究机构CSIRO在90年代发明并于1996年在美国成功申请了无线网技术专利.(US ...

  6. jstl long类型数据转换为日期格式

    一.有WEB-INF下建立一个datetag.tld <?xml version="1.0" encoding="UTF-8"?> <tagl ...

  7. SQL创建链接服务器

    二.--创建链接服务器 exec sp_addlinkedserver  'srv_lnk','','SQLOLEDB','远程服务器名或ip地址' exec sp_addlinkedsrvlogin ...

  8. 单调递增最长子序列(南阳理工ACM)

    描述 求一个字符串的最长递增子序列的长度如:dabdbf最长递增子序列就是abdf,长度为4 输入 第一行一个整数0<n<20,表示有n个字符串要处理随后的n行,每行有一个字符串,该字符串 ...

  9. php面向对象(一) 初窥

    初窥php面向对象 1.类:类就是属性和方法的集合 是一个抽象的概念比如生活中的“人”,"汽车"2.对象:对象是具体的事物 比如一叫“小强”的人 一辆叫“奥迪a7”的汽车3.类和对 ...

  10. 《自己动手写操作系统》pmtest2笔记

    ;DispReturn模拟一个回车的显示,(让下一个要显示的字符在下一行的开头处显示),其中edi始终指向要显示的下一个字符的位置.;   ------------------------------ ...