主存各存储单元
的空间位置
是由单元地址号
来表示的,
而地址总线
是用来指出存储单元地址号
的,根据该地址可读出或写人一个存储字
不同的机器存储字长
也不同,为了满足字符处理的需要,常用8位二进制数表示一个字节
,因此存储字长都取8(bit)的倍数
通常计算机系统既可按字
寻址,也可按字节
寻址
例如IBM 370机器(记为A机器)的字长为32位
,
它可按字节
寻址,即它的每一个存储字包含4个可独立寻址的字节
,
其地址分配如图(a)所示
字节地址 | Note | ||||
---|---|---|---|---|---|
字 地 址 | 0 | 1 | 2 | 3 | w1 |
4 | 5 | 6 | 7 | w2 | |
8 | 9 | 10 | 11 | w3 | |
IBM370机器 |
字地址(word address)
的二进制分别是:0000,0100,1000
该矩阵下,每一行代表该机器的一个字(word);
字地址是用(构成)该字
(的4个字节中的)高位字节的地址来表示
故其字地址
是4(4Byte)整数倍,正好用地址码
的末两位
来区分同一字
的4个字节的位置
对24位地址线
的主存而言,按字节
寻址的范围是16 M(
2
24
=
2
4
×
2
20
=
16
M
(
B
y
t
e
)
2^{24}=2^{4}\times 2^{20}=16M(Byte)
224=24×220=16M(Byte),
字
,也就是同样位数的地址线的寻址范围会因为不同的机器而不同);字
寻址的范围为4M(按字节寻址的范围宽度/存储字长=
2
24
/
4
=
4
⋅
2
20
=
4
M
2^{24}/4=4\cdot{2^{20}}=4M
224/4=4⋅220=4M)
但对PDP -11机(记为B机器)而言,其字长为16位
,字地址是2(Byte)的整数倍.
它用低位字节
的地址来表示字地址
字节地址 | Note | ||
---|---|---|---|
字 地 址 | 0 | 1 | w1 |
2 | 3 | w2 | |
4 | 5 | w3 | |
PDP-11 |
24位地址线
而言,按字节
寻址的范围仍为16 M
字
寻址的范围为8 M字节编址
,即每个地址编号
中存放1字节字节数
不同,
程序中对每个数据只给定一个地址
变量i
的地址为08 00H,字节
01H、23H、45H、67H应该各有一个内存地址
(字节地址)哪字节的地址(最高字节地址还是最低字节地址)
呢?现代的计算机系统一般采用字节(Octet, 8 bit Byte)作为逻辑寻址单位
当物理单位的长度大于1个字节时,就要区分字节序(Endianness),字节序是指处理器在处理多字节数据时,在寄存器和内存中保存字节的顺序
为了简便起见它的英文也常常表示为 Byte Order
目前在各种体系的计算机中通常采用的字节存储机制主要有两种:
Big-Endian(BE),是指数据的高字节(MSB)保存在内存的低地址中,而数据的低字节(LSB)保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
Little-Endian(LE),是指数据的高字节(MSB)保存在内存的高地址中,而数据的低字节(LSB)保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致
最高有效字节存放在前面
;最低有效字节存放在前面
保存十六进制数据01234567H(相当于32位二进制数)
>>> bin(0x01234567)
'0b1001000110100010101100111'
内存地址 | … | 0800H | 0801H | 0802H | 0803H | … |
---|---|---|---|---|---|---|
大端方式 | … | 01H | 23H | 45H | 67H | … |
小端方式 | … | 67H | 45H | 23H | 01H | … |
大端方式是先存放数据的高位字节再存放低位字节
小端方式先存放的是数据的低位字节
#include
void print_seperator(void)
{
printf("\n------------------------\n");
}
void s2u()
{
/* 探究无符号数和有符号数之间的转换 */
printf("给定2个真值x,y\ny是x的强制类型转换为无符号数后的对应值");
short x = -4321;
unsigned short y = (unsigned short)x;
/* 逆向转换实例 */
unsigned short p = 65535;
short q = (short)p;
printf("sizeof short int:%d\n", sizeof(x));
printf("x(%%d)=%d,y(%%u)=%u\n", x, y);
print_seperator();
printf("\n观察寄存器中的bit情况,一般情况下,您会发现,整形变量中的二进制串是以补码的形式存在的\n");
printf("@@check the bits value of variable x,y in the registor\n with 16(hexadecimal form)\n");
printf("x(%%hx)=%hx,y(%%hx)=%hx\n", x, y);
print_seperator();
printf("可以看到,强制转换为无符号数后得到的y,其二进制编码和有符号数x的二进制(补码)串是相同的,为了便于简写,使用16进制来标记,每个16进制数尾缀用H标识,不属于数据位!);\n x,y在计算或者以整形%d输出的时候,会转回换为真值输出:\n");
printf("有符号数x=-4321的十六进制补码是ef1fH,(附|x|=4321的十六进制为10e1H,计算x的补码确实是ef1fH\n");
printf("输出无符号数y的时候,就是将ef1fH按照无符号数%%d(%%u)解释方式输出(对应的无符号数y的真值为61215)\n");
print_seperator();
printf("强制类型转换的结果位值保持不变;仅改变了解释这些位的方式!");
// printf("x(%%x)=%x,y(%%x)=%x\n", x, y);
print_seperator();
printf("x(%%u)=%u,y(%%d)=%d\n", x, y);
printf("p(%%hx)=%hX,q(%%hx)=%hx\n", p, q);
printf("p(%%h)=%d,q(%%h)=%hd\n", p, q);
}
void l2s()
{
/* 探究不同字长之间的数的类型转换
本例以int转换为short查看效果 */
printf("给定2个真值u1,u2\n");
int u1 = 165537, u2 = -34991;
short v1 = (short)u1, v2 = (short)u2;
/* 逆向转换实例 */
printf("sizeof short int:%d\n", sizeof(u1));
print_seperator();
printf("u1(%%d)=%d,u1(%%d)=%d\n", u1, u2);
printf("再以十六进制的形式输出,最高位开始的0bit默认不显示因此32bit的十六进制数未必有8个值\n");
printf("u1(%%x)=%#x,u2(%%x)=%#x\n", u1, u2);
print_seperator();
printf("\n观察寄存器中的bit情况,一般情况下,您会发现,整形变量中的二进制串是以补码的形式存在的\n");
printf("@@check the bits value of variable u1,u2 in the registor\n with 16(hexadecimal form)\n");
printf("下面两种打印方式结果一致(可以通过输出控制符来直接截断高位字节!(只输出低位字节);此外,以十六进制输出时,可以在控制字符序列中添加一个#号,打印的时候自动添加头部的Ox(或者OX)\n");
printf("u1(%%hx)=%hx,u2(%%hx)=%hx\n", u1, u2);
printf("v1(%%hx)=%#hx,v2(%%hx)=%#hx\n", v1, v2);
print_seperator();
/* 尝试用用int 打印short的变量的补位效果 */
printf("v1(%%hx)=%#hx,v2(%%hx)=%#hx\n", v1, v2);
printf("v1(%%x)=%#x,v2(%%x)=%#x\n", v1, v2);
printf("v1(%%d)=%#d,v2(%%dx)=%#d\n", v1, v2);
print_seperator();
// printf("x(%%u)=%u,y(%%d)=%d\n", x, y);
// printf("p(%%hx)=%hX,q(%%hx)=%hx\n", p, q);
// printf("p(%%h)=%d,q(%%h)=%hd\n", );
}
void s2l()
{
/* 探究不同字长之间的数的类型转换
本例以int转换为short查看效果 */
printf("给定2个真值u1,u2\n");
short u0 = 4321;
short u1 = -4321;
unsigned short u2 = (unsigned short)u1;
/* 有符号数的short向int转换 */
int v1 = (int)u1;
/* 无符号数的short转int */
unsigned int v2 = (unsigned int)u2;
/* 逆向转换实例 */
print_seperator();
// printf("u1(%%d)=%d,u1(%%d)=%d\n", u1, u2);
printf("再以十六进制的形式输出,最高位开始的0bit默认不显示因此32bit的十六进制数未必有8个值\n");
printf("u0(%%hx)=%#hx,(int)u0(%%x)=%#x\n", u0, (int)u0);
printf("u1(%%hx)=%#hx,v1(%%x)=(int)u1=%#x,u2(%%x)=%#x,v2(%%x)=(unsigned int)u2=%#x\n", u1, v1, u2, v2);
printf("u1(%%d)=%#d,v1(%%d)=%#d,u2(%%d)=%#d,v2(%%d)=%#d\n", u1, v1, u2, v2);
print_seperator();
}
int main(int argc, char const *argv[])
{
printf("section1:short转unsigned short🎈🎈🎈🎈\n");
s2u();
printf("section2:int转short:🎈🎈🎈🎈\n");
l2s();
printf("section3:short转int:🎈🎈🎈🎈\n");
s2l();
return 0;
}
section1:short转unsigned short🎈🎈🎈🎈
给定2个真值x,y
y是x的强制类型转换为无符号数后的对应值sizeof short int:2
x(%d)=-4321,y(%u)=61215
------------------------
观察寄存器中的bit情况,一般情况下,您会发现,整形变量中的二进制串是以补码的形式存
在的
@@check the bits value of variable x,y in the registor
with 16(hexadecimal form)
x(%hx)=ef1f,y(%hx)=ef1f
------------------------
可以看到,强制转换为无符号数后得到的y,其二进制编码和有符号数x的二进制(补码)串是
相同的,为了便于简写,使用16进制来标记,每个16进制数尾缀用H标识,不属于数据位!);
x,y在计算或者以整形-2074805712输出的时候,会转回换为真值输出:
有符号数x=-4321的十六进制补码是ef1fH,(附|x|=4321的十六进制为10e1H,计算x的补码确
实是ef1fH
输出无符号数y的时候,就是将ef1fH按照无符号数%d(%u)解释方式输出(对应的无符号数y的
真值为61215)
------------------------
强制类型转换的结果位值保持不变;仅改变了解释这些位的方式!
------------------------
x(%u)=4294962975,y(%d)=61215
p(%hx)=FFFF,q(%hx)=ffff
p(%h)=65535,q(%h)=-1
section2:int转short:🎈🎈🎈🎈
给定2个真值u1,u2
sizeof short int:4
------------------------
u1(%d)=165537,u1(%d)=-34991
再以十六进制的形式输出,最高位开始的0bit默认不显示因此32bit的十六进制数未必有8个
值
u1(%x)=0x286a1,u2(%x)=0xffff7751
------------------------
观察寄存器中的bit情况,一般情况下,您会发现,整形变量中的二进制串是以补码的形式存
在的
@@check the bits value of variable u1,u2 in the registor
with 16(hexadecimal form)
下面两种打印方式结果一致(可以通过输出控制符来直接截断高位字节!(只输出低位字节);此外,以十六进制输出时,可以在控制字符序列中添加一个#号,打印的时候自动添加头部的Ox(或者OX)
u1(%hx)=86a1,u2(%hx)=7751
v1(%hx)=0x86a1,v2(%hx)=0x7751
------------------------
v1(%hx)=0x86a1,v2(%hx)=0x7751
v1(%x)=0xffff86a1,v2(%x)=0x7751
v1(%d)=-31071,v2(%dx)=30545
------------------------
section3:short转int:🎈🎈🎈🎈
给定2个真值u1,u2
------------------------
再以十六进制的形式输出,最高位开始的0bit默认不显示因此32bit的十六进制数未必有8个
值
u0(%hx)=0x10e1,(int)u0(%x)=0x10e1
u1(%hx)=0xef1f,v1(%x)=(int)u1=0xffffef1f,u2(%x)=0xef1f,v2(%x)=(unsigned int)u2=0xef1f
u1(%d)=-4321,v1(%d)=-4321,u2(%d)=61215,v2(%d)=61215
------------------------
scanf 函数处理格式化输入转换
int fscanf(FILE *stream, const char *format, ...)
fscanf函数根据格式串 format
格式串 format通常包括转换说明,它用于指导对输入进行解释。
格式字符串中可以包含下列项目:
*
,一个指定最大字段宽度的数(可选)、一个指定目标字段宽度的字符(h、l或z)(可选)以及一个转换字符组成。
*
,例如%*s
,则将跳过对应的输入字段,并不进行赋值。合法的转换字符如表
d、i、n、o、u和x
之前可以加上前缀h
。l
。e、f和g
前可以加上字母l
。e、f和g
前可以加上字母L。int fprintf(FILE *stream, const char *format, ...)
-
指定被转换的参数在其字段内左对齐+
指定在输出的数前面加上正负号空格
如果第一个字符不是正负号,则在其前面加上一个空格0
对于数值转换,当输出长度小于字段宽度时,添加前导О进行填充#
指定另一种输出形式。
一个数值
点号
,用于分隔字段宽度和精度。表示精度的数
长度修饰符h、l或L
。
*
指定,