可以提供排版的网站,友情链接怎么弄,中国建设银行舟山分行网站,广州培训+网站开发1.整数在内存中的存储
我们之前就了解过整数的二进制写法分别有3种#xff0c;分别为原码#xff0c;反码#xff0c;补码。整型在内存中存储的是补码。
原码#xff0c;反码#xff0c;补码都有自己的符号位和数值位#xff0c;符号位为1时#xff0c;则表示负数分别为原码反码补码。整型在内存中存储的是补码。
原码反码补码都有自己的符号位和数值位符号位为1时则表示负数符号位为0时则表示正数。
注意
正数的原码反码补码相同。
而负数的原码反码补码是不一样的。
负数的原码就是将其数字转换为二进制得到原码。
对原码除符号位外的数值位进行取反得到反码。
反码1 得到补码。
以上是有负数的原码得到其补码的过程。
由负数的补码得到原码也可以通过 对补码进行取反加1得到其原码。
2.大小端字节序和字节序判断
我们先看一段简单的代码
如下图 变量a原本设置的是0x11223344可通过vs编译器调试发现其在内存中的存储顺序恰好是反过来的。
这是为什么呢
这就涉及到来大小端字节序的问题。
2.1 大小端的含义
首先我们要清楚当储存的数据大小超过一个字节时其在内存中的存储顺序就有了大端字节序存储和小端字节序存储。
1.大端字节序存储是指数据的低字节内容保存在内存中的高地址处而高细节内容保存在内存中的低地址处。 如图11相对于22来说11是高字节内容22是低字节内容。
所以将11放在低地址处22放在放在高地址处。33和44依此类推。
2. 小端字节序存储是指数据的低字节内容保存在内存中的低地址而高字节内容保存在内存中的·高地址处。
如图 通过以上了解的内容可知为什么数据在vs中调试在内存中的存储顺序是倒过来的。
原因是vs是小端字节序存储。
2.2 判断大小端字节序
虽然我们知道了vs是小端字节序存储那我们如何来证明呢
我们可以通过代码来实现
int system()
{int a 1;char* p a;return *p;
}
int main()
{int ret system();if (ret 1){printf(小端字节序存储);}else{printf(大端字节序存储);}return 0;
}
看图 如上图所示a的16进制位分别在大端字节序和小端字节序的顺序排序。
我们又设计了一个char* p指针来存储a所以p指向了a的第一个字节的内容当我们对p进行解引用时一次也只能访问一个字节而一个字节恰好是2个16进制位。
返回*p的值用ret来保存*p我们就可以通过ret的值来判断大小端字节序存储了。
当返回值位1时是小端字节序存储返回值位0时是大端字节序存储。
用vs运行代码 3.练习题
接着来几道练习题巩固一下知识。
练习1
#include stdio.h
int main()
{char a -1;signed char b-1;unsigned char c-1;printf(a%d,b%d,c%d,a,b,c);return 0;
}
我们一开始看到该题可能会有点蒙不过别慌张我们分析下代码。
该题创建了 a,b,c 三个变量分别是char signed char unsigned char 类型。
这时很疑惑明明是 -1 是个整型数据却用了一个不符合整型类型的变量来存储。
但这是允许的。只不过会发生数据的截断影响最终打印的结果。
这种题思路是一样的。
我们先以a为例
我们先把 -1 的原码写出来为1000000000000000000000000001
在对其取反为 11111111111111111111111111111110得到反码。
在对反码加1得到补码为11111111111111111111111111111111便是-1的补码。
我们知道整型数据在内存中是以补码的形式存储的但是由于变量a是char类型的所以a只能存储一个字节大小的数据也就是8个比特位。则会发生数据的截断。
优先截断低字节的数据这时便会截断8个比特位的内容存储到a中。 则这时a中存储的是11111111
(补充char类型是signed类型的还是unsigned类型的是取决于编译器的再vs中char默认为是signed char 类型的。)
最后我们要以整型打印所以要对a进行整型提升。
整型提升规则有符号数据补符号位无符号数据不0
由于a是signed char 型属于有符号型则对a进行整型提升后为
11111111111111111111111111111111
整型提升后得到的还是补码。所以我们要求出其原码。
接着对补码进行取反1的操作的到原码
10000000000000000000000000000001
由于是以%d的形式打印也就是将a看作有符号数据所以此时的最高位为符号位。
通过原码计算可知最终a的值为 -1。
接着来分析b
由于b的类型和a在vs中的数据类型是一样的并且赋值都为-1所以和以上a的推算是一模一样的。
最后来分析c
一样的步骤把 -1 的原码写出来 为 1000000000000000000000000001原码
接着对原码取反为 11111111111111111111111111111110 反码
反码加1得到补码为 11111111111111111111111111111111补码
也由于 c 是unsigned char 类型的只能存储一个字节大小的数据也就是8个比特位。
则发生截断 这时c存储的是11111111。
接着对其进行整型提升由于c是unsigned char 类型则此时最高位不是符号位了所以补0.
得到 00000000000000000000000011111111 此时得到的也是补码。
但由于c是无符号数据则原码反码补码相同。
通过原码计算得 c为255。
运行代码 练习2
#include stdio.h
int main()
{char a[1000];int i;for(i0; i1000; i)
{a[i] -1-i;}printf(%d,strlen(a));return 0;
}
一开始看到这道题是肯定会懵一下的。不过别慌张冷静分析。
这里涉及到一个循环后面有涉及到了一个strlen的计算我们知道strlen计算的是 /0 之前的长度。而 \0 的ASCII值为0所以计算的是0之前的长度。
遇到这种题有一个圆形图解法。下面是char 的圆图。 如上图我们对二进制的1弄成一个圆也就是循环了。
由于题目是减1那就反过来则0的前面就有255个则长度就为255.
运行代码如下图也是255. 练习3
#include stdio.h
unsigned char i 0;
int main()
{for(i 0;i255;i){printf(hello world\n);}return 0;
}
这也可以根据圆形图解法来解决不过是unsigned char 类型的圆 由此得出 i 的 取值范围 0~255所以 i 永远小于等于255则循环条件恒成立这样就会现如死循环。
练习4
#include stdio.h
int main()
{int a[4] { 1, 2, 3, 4 };int *ptr1 (int *)(a 1);int *ptr2 (int *)((int)a 1);printf(%x,%x, ptr1[-1], *ptr2);return 0;
}
这道题是有点复杂的我们还是冷静分析。
线分析ptr1如下图 由上图轻易得到ptr[-1]为4。
难点就在ptr2 我们知道数组名在大部分就是条件下是首元素地址所以此时a是首元素地址 但是被强制转换成int 类型了强制转换成 int 型后进行加1我们知道整型加1和整数加1的道理差不多这时加1就是跳过了1个字节。我们将数组的内容转换成16进制的形式。 上面分析得知整型加1就是跳过一个字节而2个16进制位就是一个字节。而a中又是int类型的存了4个字节的数据。如下图所示 但又因为在vs中是小端字节序存储所以我们要将ptr2还原。
还原得到 02000000。
运行代码如下图