最近读《深入》一书遇到了非常多的问题,内容太杂较深,外国人的语言习惯也不一样,翻译过来的书翻译的怪怪的。所以读书进展很慢,我打算进度放缓,主攻《汇编语言》一书。

1.字

每台计算机都有一个字长,指明整数和指针的标称大小,同时字长也部分决定了虚拟地址空间的大小,如32位的80386CPU,其虚拟地址空间最大为4GB(2^32=4,294,967,296。4,294,967,296/1024/1024/1024=4GB,共有4,294,967,296个存储器单元地址,共4,294,967,296byte)。但是字长与地址总线没有对应关系。

2.数据大小

丢的文章中有篇写到了。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <climits>
using namespace std;



int main()
{
int n_int = INT_MAX;
short n_short = SHRT_MAX;
long n_long = LONG_MAX;
long long n_llong = LLONG_MAX;

cout << "int is " << sizeof(int) << " bytes." << endl;
cout << "short is " << sizeof(n_short) << " bytes." << endl;
cout << "long is " << sizeof(long) << " bytes." << endl;
cout << "long long is " << sizeof(long long) << " bytes." << endl;
cout << "char* " << sizeof(char*) << " bytes." << endl;
cout << endl;

cout << "Maximum values:" << endl;
cout << "int:" << n_int << endl;
cout << "short:" << n_short << endl;
cout << "long:" << n_long << endl;
cout << "long long:" << n_llong << endl << endl;

cout << "Minimum int value =" << INT_MIN << endl;
cout << "Bits per byte =" << CHAR_BIT << endl;

system("pause");
return 0;
}

数据大小

注意char*!也可以试试void *,也是8字节

3.寻址和字节顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include<iostream>
typedef unsigned char *byte_pointer; //定义一个声明char型指针的方式,用于强制类型转换,不论原来是什么,指针指向的被看成是字符
void show_bytes(byte_pointer start, int len)//参数:char型指针start和长度
{
int i;
for (i = 0; i < len; i++)
{
printf("%.2x", start[i]);//
}
printf("\n");
}

void show_int(int x)
{
show_bytes((byte_pointer)&x, sizeof(int));//对x取地址,int的存储长度
}

void show_float(float x)
{
show_bytes((byte_pointer)&x, sizeof(float));
}

void show_pointer(void *x)//void表示没有相关联的数据类型
{
show_bytes((byte_pointer)&x, sizeof(void *));
}

void test_show_bytes(int val)
{
int ival = val;
float fval = float(ival);
int *pval = &ival;
int *ppval = &val;
show_int(ival);
show_float(fval);
show_pointer(pval);
show_pointer(ppval);
}
int main()
{
test_show_bytes(12345);
system("pause");
return 0;
}

结果

结果的第一和第二行是12345的整型和浮点型(浮点型为什么是这样以后在写)的十六进制表示,第三行是pval内的值,即ival的地址,第四行是ppval内的值,即val的地址。

34 fa 6f f1 fc和下面第一行的fc f1 6f fa 34有这显而易见的对应关系,这就牵扯到字节顺序。

pval 0x000000fcf16ffa34 int *

ppval 0x000000fcf16ffb90 int *

fc f1 6f fa 34是本应是真正的值,只是在存储空间中并不是按照这种对应关系存储的。细心的话你会发现12345的十六进制是3039而不是3930,显然,它是倒过来放的。低位有效数字在前,高位数字在后。这就是所谓的“小端法”。

假定十六进制数字0x1234567,其小端法表示和大端法表示分别为:

大端法:

0x100 0x101 0x102 0x103
01 23 45 67

小端法:

0x100 0x101 0x102 0x103
67 45 23 01

tips:十六进制与二进制转化。一个内存单元一字节,8bit,一个单元分为两组转化为十六进制。

转换

《深入》一书中写到“大多数Intel兼容机都采用这种规则(小端法)”,“许多比较新的微处理器使用双端法”。

一些系统和机器的情况如下表:

表格

(Windows为32位)

在64位的情况下,指针用的是八字节!!!而32位的只有四字节。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <iostream>
using namespace std;

int main()
{
int a=3;
int b=a;
int *p1=&a;
int *p2=&b;
cout<<p1<<' '<<p2<<endl;
system("pause");
return 0;
}

这段代码在我的电脑上用不同编译器运行有不同的表现形式。(Windows10 64位 i7-3740MQ)

GCC 6.3.0(MinGW)

0x61ff14 0x61ff10

VS2017

0000007B8F58FD04 0000007B8F58FD24

注意到GCC的就是内存单元的编号,差了4字节,说明int aint b是相邻存储的,但是编号形式是0x61ff14,是十六进制的。而VS中也是十六进制,相差20,十进制是32,也是4字节。GCC是按字节编号,而VS是按位编号。

回到3930000000e44046这两个数字,其真实数字是3039 00004640 e400,其二进制分别是:

0011 0000 0011 1001 0000 0000 0000 0000

0100 0110 0100 0000 1110 0100 0000 0000

在补0对齐后

0000 0000 1100 0000 1110 0100 0000 0000 0000 00

0100 0110 0100 0000 1110 0100 0000 0000

注意中间有一部分是相同的,这就涉及到浮点数如何表示的问题了。