一、整形计算机表示及内存中的存储
1.整形计算机表示
数值有不同的表示形式——2进制【0b开头】、8进制【0开头】、10进制【没有前缀】、16进制【0x开头】等。
2进制序列写成16进制序列 时,4个比特位和为一个【分别对应2的0、1、2、3次方】,每两个放到一块,前边再加上0x
内存中本质还是2,但是为了我们分析/编译器显示方便,一般会表示16进制。
整数的二进制的三种表示形式:
原码:直接通过正负的形式写出的二进制序列就是原码
反:原码符号位不变,其他位按位取反得到的就是反码
补:反码+1
另外:原码除了可以通过补码产生的逆运算得到,也可以由补码+1,在按位取反(符号位除外)得到。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位表示各不相同。
正整数
正整数原反补相同
负整数
写出原码,根据计算规则算出反码补码。
2. 整形内存表示——补码
对于整形,计算机存放的其实是补码的二进制序列。
原因
在计算机系统中,数值一律用补码来表示和存储。
原因
使用补码,可以将符号位和数值域统一处理;-----1
同时,加法和减法也可以统一处理(CPU****只有加法器)-----2
此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。-----3
二、大小端字节序详解
我们已经知道整数在计算机内部统统存的都是补码,但是我们可以看到他们显示的顺序好像跟我们以为的补码不太一样,这里就涉及到了大小端字节序的问题。
1. 什么是大小端字节序
大端(存储):数据低位存储在内存的高地址、数据高位存储在内存的低地址。
小端(存储):数据高位存储在内存的高地址、数据低位存储在内存的低地址。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-npuTNjzc-1657982340352)(C:\Users\19271\AppData\Roaming\Typora\typora-user-images\image-20220715142900324.png)]
2.为什么会有大小端字节序之分
在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8 bit。
但是在C语言中除了8 bit的char之外,还有16 bit的short型,32 bit的long型(要看具体的编译器)
另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
简言之,只要超过两个字节以上就有顺序问题,char、double等都有——内存存储问题。
但是存储顺序——五花八门,其他的太麻烦,正放反放两种比较方便。
【画图时无特殊要求时,低地址到高地址是根据自己习惯决定的】
补充
大端存储和小端存储都取决于硬件,市面上大部分都是小端存储,这些跟编译器没有什么关系
例如,x86结构就是小端模式
3.一道真题
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)
所以我们只要拿到它的第一个字节存储的值看是0还是1,就可以判断。——这里体现了指针类型的意义。
所以,答案可以为
#include <stdio.h>
int check_sys()
{
int a = 1;
return *(char*)&a;
}
int main()
{
int ret = check_sys();
if (ret == 1)
printf("小端\n");
else
printf("大端\n");
return 0;
}
补充:【&a,是地址编号,本质上是一个整形】——所以打印的时候可以以%d形式打印。
4.练习题
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;
}
2)下面程序输出什么?
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
3)下面程序输出什么?
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
4)
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
5)
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
6)
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
7)
#include <stdio.h>
unsigned char i = 0;
int main()
{
for(i = 0;i<=255;i++)
{
printf("hello world\n");
}
return 0;
}
三、重点强调
1.整数内存存储形式——补码
2.整数运算——补码,原码/其他形式打印
3.特别小心无符号数,同时小心strlen的返回值。
4.截断的方法——从补码的低位开始,整型提升方法——复习操作符之整形提升算数转换那块。
5.大小端字节序存储这块知识多与指针练习题紧密结合,特别小心。
|