intel系列的cpu是小尾(Little Endian),高位的字节放在前面,低位的字节放到后面,如果网络传输等等需要进行字节转换,因为最初是摩托罗拉系列的cpu(主要应用于工控机,arm系列或者power pc系列)先出来混的,他们的cpu是相反的,大尾(Big Endian)的,所以他们的cpu在网络上传输是不需要转换的
1 字节序
大多数处理器中内存是可以以字节为单位进行寻址的,当数据类型(比如int、long)大于1个字节时,其所占的字节在内存中的顺序存在两种模式,分别是小端模式(Little Endian)和大端模式(Big Endian)。小端模式是低位字节放在低地址,而大端模式则是高位字节放在低地址。
由于不同的计算机系统采用不同的字节序存储数据,同样一个4字节的32位整数,在内存中存储的方式就不同. 字节序分为小尾字节序(Little Endian)和大尾字节序(Big Endian), Intel处理器大多数使用小尾字节序, Motorola处理器大多数使用大尾(Big Endian)字节序;
01
|
23
|
45
|
67
|
Byte3
|
Byte2
|
Byte1
|
Byte0
|
高位字节--
à
---------
à
--------------
à
低位字节
|
内存地址序号
|
字节在内存中的地址
|
16
进制值
|
0x03
|
Byte3
|
01
|
0x02
|
Byte2
|
23
|
0x01
|
Byte1
|
45
|
0x00
|
Byte0
|
67
|
01
|
23
|
45
|
67
|
Byte3
|
Byte2
|
Byte1
|
Byte0
|
高位字节--
à
---------
à
--------------
à
低位字节
|
内存地址序号
|
字节在内存中的地址
|
16
进制值
|
0x03
|
Byte0
|
67
|
0x02
|
Byte1
|
45
|
0x01
|
Byte2
|
23
|
0x00
|
Byte3
|
01
|
#include<stdio> void foo(short * _p_module_id) { printf("foo():module ID is %d.\n", * _p_module_id); * _p_module_id=4; } int main() { int module_id=3; foo((short *)module_id); printf("main():module ID is %d.\n", module_id); return 0; }
a
|
b
|
c
|
\0
|
s[0]
|
s[1]
|
s[2]
|
s[3]
|
|
内存地址序号
|
16
进制值
|
指针P的位置
|
0xbffeadf7
|
\0
|
p+3
|
0xbffeadf6
|
c
|
p+2
|
0xbffeadf5
|
b
|
p+1
|
0xbffeadf4
|
a
|
p
|
下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:
short int x; char x0, x1; x = 0x1122; x0 = ((char*)&x)[0]; // 低地址单元 x1 = ((char*)&x)[1]; // 高地址单元 printf("x0 = 0x%x, x1 = 0x%x /n", x0, x1); // x0 = 0x22, x1 = 0x11
输出:x0 = 0x22, x1 = 0x11
则表示当前编译器使用的是小端模式
2.使用C语言判断处理器的大小端
int checkCPU() { { union w { int a; char b; } c; c.a = 1; return (c.b == 1); } } printf("checkCPU:%d/n", checkCPU()); // Output "checkCPU:1"
输出:checkCPU:1
表示处理器为小端模式。
***************************************************************************************************************************************************************************************
下面代码示范了两种检测系统字节序的方法。
第一种方法,使用强制类型转换的方式。C 语言在把占用2个字节的 short 变量强制转换为 char 之后,会把 short 变量的首地址赋给 char 变量,可以根据 char 变量的值判断系统字节序是 大端 还是 小端。
第二种方法,利用 联合类型 的特性。联合类型 共享同一段内存,首地址是相同的。
测试环境:
ubuntu 10.04 amd 64.
/******************* * 文件名:endian.c ******************/ #include <stdio.h> /********************************************************* * 使用类型的强制转换实现little-endian与big-endian的判断 ********************************************************* * 返回值: * 1 表示是小端字节序。 * 0 表示不是小端字节序。 *********************************************************/ int is_little_endian_a(void) { unsigned short flag = 0x4321; if(*(unsigned char*)&flag == 0x21) return 1; else return 0; } /********************************************************************************* * 利用联合的特点来判断little-endian与big-endian ********************************************************************************* * 返回值: * 1 表示是小端字节序。 * 0 表示是大端字节序。 * -1 表示不能使用这种方法确定字节序。比如有的机器的 short 长度不是 2 。 ********************************************************************************/ int is_little_endian_b(void) { union endian_un{ short var; char bits[sizeof(short)]; }; union endian_un flag; flag.var=0x0102; //判断低位和高位的存储内容,确定是何种方式 if(sizeof(short) == 2){ if(flag.bits[0] == 1 && flag.bits[1] == 2) return 0; else if(flag.bits[0] == 2 && flag.bits[1] == 1) return 1; else return -1; } return -1; } int main(void) { int type = 0; type = is_little_endian_a(); if (1 == type) printf("judged by first method, little-endian\n"); else if (0 == type) printf("judged by first method, big-endian\n"); type = is_little_endian_b(); if (1 == type) printf("judged by second method, little-endian\n"); else if (0 == type) printf("judged by second method, big-endian\n"); else printf("can't judge it\n"); return 0; }
运行截图