做建筑看那些网站,厨师培训机构,个人网站只能用作博客,网页布局的目的目录
前言
一、整形数据在内存中的存储
二、大小端字节序
三、大小端字节序的判断
四、字符型数据在内存中的存储
总结 前言 本文主要讲述整型包括字符型是如何在内存中存储的#xff0c;涉及到大小端字节序这一概念#xff0c;还有如何判断大小端#xff0c;希望对大… 目录
前言
一、整形数据在内存中的存储
二、大小端字节序
三、大小端字节序的判断
四、字符型数据在内存中的存储
总结 前言 本文主要讲述整型包括字符型是如何在内存中存储的涉及到大小端字节序这一概念还有如何判断大小端希望对大家有所帮助 ❤️感谢支持点赞关注不迷路❤️ 本文内容涉及到整形提升如不了解主页中可查看详细两篇结合起来看更深入 一、整形数据在内存中的存储 我们都知道。整数的2进制表示有3种即原码、反码、补码。 有符号的整数三种表示方法均有符号位和数值位两部分符号位都是用0表示“正”用1表 示“负”最高位的一位是被当做符号位剩余的都是数值位。 原码直接将数值按照正负数的形式翻译成二进制得到的就是原码。反码将原码的符号位不变其他位依次按位取反就可以得到反码。补码反码1就得到补码。
正整数的原、反、补码都相同。
负整数的三种表示方法各不相同。 对于整形来说数据存放内存中其实存放的是补码。 为什么呢 在计算机系统中数值⼀律用补码来表示和存储。 原因在于使用补码可以将符号位和数值域统一处理 同时加法和减法也可以统一处理CPU只有加法器此外补码与原码相互转换其运算过程是相同的都是取反加1不需要额外的硬件电路。 主页·位操作符有详细举例 二、大小端字节序 运行以下代码在vs32位调试窗口观察其在内存中的存储情况
#include stdio.hint main()
{int a 0x11223344;return 0;
}
内存调试窗口 0x0058FB3C是a在内存中的首地址
发现a 0x11223344它在内存中存储的却是 44 33 22 11是倒着存储的。相信我们平时调试的时候肯定会有这样的疑问这就涉及到了大小端字节序了。 什么是大小端 其实超过一个字节的数据在内存中存储的时候就有存储顺序的问题按照不同的存储顺序我们分为大端字节序存储和小端字节序存储下面是具体的概念 大端存储模式 是指数据的低位字节内容保存在内存的高地址处而数据的高位字节内容保存在内存的低地址处。小端存储模式 是指数据的低位字节内容保存在内存的低地址处而数据的高位字节内容保存在内存的高地址处。 解释说明例如上面的 a 0x11223344我们按照数学方式读这个数时44是不是个位和十位。它相比于前面的 112233 是不是算低位。44 就是一个低位字节内容VS是以小端模式存储数据的所以 44 就存储在内存的低地址处其余的就按顺序往高处存储这样我们看到的就是 44 33 22 11了。那么假如我们用的是大端模式存储数据的那么我们看到的就是 11 22 33 44 11在内存中对应的是低地址44 是高地址。 为什么有大小端 为什么会有大小端模式之分呢 这是因为在计算机系统中我们是以字节为单位的每个地址单元都对应着⼀个字节⼀个字节为8 bit 位但是在C语言中除了8bit的 char 之外还有16bit的 short 型32bit的 long 型要看具体的编译器另外对于位数大于8位的处理器例如16位或者32位的处理器由于寄存器宽度大于一个字节那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。 例如⼀个 16bit 的 short 型 x 在内存中的地址为 0x0010x 的值为 0x1122 那么0x11为高字节0x22为低字节。对于大端模式就将0x11放在低地址处即0x0010中0x22放在高地址处即0x0011中。小端模式刚好相反。我们常用的X86 结构是小端模式而 KEIL C51 则为大端模式。很多的ARMDSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。 三、大小端字节序的判断 判断大小端其实很简单定义 int a 116进制为 0x 00 00 00 01我们只需要访问其首地址对应的字节内容即可小端会以 0x 01 00 00 00 从低地址往高地址排放大端会以 0x 00 00 00 01 从低地址往高地址排放。 如下一小段代码即可
#include stdio.hint check_sys()
{int a 1;return *(char*)(a);
}int main()
{int ret check_sys();if (ret 1){printf(小端\n);}else if (ret 0){printf(大端\n);}return 0;
}
运行结果VS 四、字符型数据在内存中的存储 字符型其实也属于整形范畴存储的是其ASCII码值。 我们可以先观察以下代码
#include stdio.hint main()
{char a -1;signed char b -1;unsigned char c -1;printf(a%d, b%d, c%d\n, a, b, c);return 0;
}
运行结果 解疑
首先我们知道字符型变量以%d打印时是要发生整形提升的。然后a为char类型vs中char类型默认为有符号字符型也就是等同于 signed char所以a整形提升是要看符号位的-1的补码是11111111 11111111 11111111 11111111a大小只有一个字节存储时会发生截断取后8位a其补码为11111111整形提升后 11111111 11111111 11111111 11111111以%d打印的是原码再转为原码为10000000 00000000 00000000 00000001因此打印的还是-1b与a一样然后就是cc是无符号字符形c的补码还是1111111整形提升无符号整形提升高位补0也就是 00000000 00000000 00000000 11111111再转为原码因为是无符号整形原反补相同所以原码还是 00000000 00000000 00000000 11111111打印出来就是255。 在看这段代码
#include stdio.hint main()
{char a -128;printf(%u\n, a);printf(%d\n, a);return 0;
}
运行结果 解疑
我们发现以%u无符号整形方式打印时打印出的是一个非常大的数字以%d打印还是原数值那么为什么会这样呢首先a以%u打印时还是会发生整形提升-128有点大我们先算出-128的原码为 10000000 00000000 00000000 10000000取反加1算出-128的补码为 11111111 11111111 11111111 10000000截断后 a 的补码就是10000000以%u打印虽然是以无符号整形打印但是整形提升时是根据原类型进行提升的原类型为char有符号字符型所以高位补符号位1即 11111111 11111111 11111111 10000000。然后%u就发挥作用了要把整形提升后的这个补码看成无符号整形这时候原反补就相同原码就是 1111111 11111111 11111111 10000000打印出来的结果就是上图中很大的数字我们可以借助计算器验证以%d打印时接着2中整形提升后的补码 11111111 11111111 11111111 10000000这里是以%d打印所以要看成有符号的整形其原码就要进行取反加1即 10000000 00000000 00000000 10000000打印出来就是-128 再看这段代码
#include stdio.hint main()
{char a 128;printf(%u\n, a);printf(%d\n, a);return 0;
}
运行结果 解疑
我们发现128的结果与-128的结果相同这又是为什么其实我们自己再重新算一下就会发现a存储时补码都是 10000000因为128与-128的补码后8位是完全相同的截断时值就相同。算一个特殊情况因为a的值相同所以后续以%u或者%d打印时效果也相同。 通过以上例题我们可以再推导一下char型变量有符号的存储范围为啥是 -128~127了还有 unsigned char 为啥是 0~255
我们画图分析 如此我们可以画成一个圆 这就是 char 类型为什么存储范围是-128~127哪怕赋值的数字超过这个范围也会被截断在这个范围内。 这就是unsigned char 存储范围为什么是0~255。 其实signed short 和 unsigned short 类型数据也可以画圆圈表示int也可以这里如果感兴趣可以自己画着试试。同上即可 总结 以上就是本文的全部内容希望对你有所帮助。