0%

输入数字判断CPU是大端还是小端模式

说明

前几天做了一个笔试题目,是输入一个数字,16进制的,类似 0x12345678 这种的,当时就想应该还是很好判断的,直接取数字的地址,然后取相应的位计算大小即可,但是通过率一直是0。一直在分析原因,由于他需要输入数据,当时也没多想,反正一直就没有做出来。知道前两天想到了一个点,存储数据最方便的肯定是字符串呀,如实今天上午花了点时间,重新写了一些,也不知道有没有通过率,反正当做是复习知识点了。

概念与详解

在各种体系的计算机中通常采用的字节存储机制主要有两种: Big-Endian和Little-Endian,即大端模式和小端模式。
Big-Endian和Little-Endian的定义如下:

1) Little-Endian:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端,如Intel的8086系列。
2) Big-Endian:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端,如PowerPC处理器。

举个例子,比如16进制数字 0x12345678 在内存中的表示形式为:

大端模式:

adress 0x2000 0x2001 0x2002 0x2003
data 0x12 0x34 0x56 0x78

小端模式:

adress 0x2000 0x2001 0x2002 0x2003
data 0x78 0x56 0x34 0x12

小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
大端模式 :符号位的判定固定为第一个字节,容易判断正负。

为什么会有大小端模式之分呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的x86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

如何判断大小端

直接取整数的地址,用short两位的性质才判断即可:

1
2
3
4
5
6
int i=1;   
char *p=(char *)&i;
if(*p == 1)
cout << "Little-Endian" << endl;
else // (*p == 0)
cout << "Big-Endian" << endl;

或者使用联合体

1
2
3
4
5
6
7
8
9
10
11
12
//return 1 : little-endian
// 0 : big-endian
int checkCPUendian()
{
union {
unsigned int a;
unsigned char b;
} c;

c.a = 1;
return (c.b == 1);
}

总结做题

一个输入一个输出,而且大小端肯定是会变的,用一个字符串就能完美替代,具体代码如下:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <string>
using namespace std;

// ** 功能:判断当前操作系统大小端的函数
// ** 输入:一个字符串,要求是十进制的格式,Eg:0x1A2B3C4D
// ** 输出:-1: 无法判断/ 0:小端模式/ 1:大端模式
int judgeEndian(string str)
{
// 首先字符串去头("0x"的头部)
str = str.substr(2, str.size()-1);

// 然后去掉不能判断的(长度是奇数的可以)
int size = str.size(), flag = 0;
if( !(size%2) ) {
for(int i = 0; i < size/2; i+= 2) {
// cout << str.substr(i, 2) << " | " << str.substr(size-2-i, 2) << endl;
if(str.substr(i, 2) != str.substr(size-2-i, 2)){
flag = 1;
break;
}
}
if(flag == 0) {
cout << " can not jundge! ";
return -1;
}
}

// 下面开始计算
// 直接转换成16进制
int num = stoi(str, nullptr, 16);
// printf("%X \r\n", num);
// printf("%X \r\n", ((char*)&num)[0]);

// 下面是两个尾部值
short int orgEnd = stoi(str.substr(size-2, 2),nullptr, 16); //原本值由字符串转化而来
short int trsEnd = ((char*)&num)[0]; //转化值由整数经过存储,然后取地址得到

if(orgEnd == trsEnd) {
cout << "Little-Endian! ";
return 0;
}
else {
cout << "Big-Endian! ";
return 1;
}

}

int main()
{
string str;
cin >> str;
judgeEndian(str);

return 0;
}

总结

没有什么值得特别总结的吧,感觉还是多加练习多多刷题就行!

-------------本文结束感谢您的阅读-------------