一、[C/C++]大小端字节序转换程序 转自:https://www.cnblogs.com/wuyepeng/p/9833273.html
计算机数据存储有两种字节优先顺序:高位字节优先(称为大端模式)和低位字节优先(称为小端模式)。
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
例子:对于内存中存放的数0x12345678来说 如果是采用大端模式存放的,则其真实的数是:0x12345678 如果是采用小端模式存放的,则其真实的数是:0x78563412
如果称某个系统所采用的字节序为主机字节序,则它可能是小端模式的,也可能是大端模式的。 而端口号和IP地址都是以网络字节序存储的,不是主机字节序,网络字节序都是大端模式。 要把主机字节序和网络字节序相互对应起来,需要对这两个字节存储优先顺序进行相互转化。 这里用到四个函数:htons(),ntohs(),htonl()和ntohl(). 这四个地址分别实现网络字节序和主机字节序的转化,这里的h代表host,n代表network,s代表short,l代表long。 通常16位的IP端口号用s代表,而IP地址用l来代表。
1
2
3
4
5
6
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
htonl 表示 host to network long ,用于将主机 unsigned int 型数据转换成网络字节顺序; htons 表示 host to network short ,用于将主机 unsigned short 型数据转换成网络字节顺序; ntohl、ntohs 的功能分别与 htonl、htons 相反。
如图,i为int类型占4个字节,但只有1个字节的值为1,另外3个字节值为0;取出低地址上的值,当其为1时则为小端模式,为0时为大端模式。
//大小端模式的判断 //方法一:利用联合体所有成员的起始位置一致, //对联合体中的int类型赋值,然后判断联合体中char类型的值的大小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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <iostream>
#include <iomanip>
using namespace std;
//signed
typedef signed char int8;
typedef short int16;
typedef int int32;
typedef long long int64;
//unsigned
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
#pragma pack(push)
#pragma pack(1)//单字节对齐
typedef struct{
uint32 ID;
uint32 Num;
uint32 Type;
uint32 lat;
uint32 lng;
uint32 alt;
uint32 speed;
}Waypoint;//Payload_Data
#pragma pack(pop)
void EndianSwap(uint8 *pData, int startIndex, int length);
int main()
{
Waypoint wp,wp_ori;
int len = sizeof(Waypoint);
cout << "size of Waypoint: " << len << endl;
wp.ID = 0x00000011;
wp.Num = 0x00002200;
wp.Type = 0xDD0CB0AA;
wp.lat = 0x00330000;
wp.lng = 0x44000000;
wp.alt = 0xABCD1234;
wp.speed = 0x12345678;
wp_ori = wp;
int i = 0;
uint8* pData = (uint8*)(&wp);
for (i = 0; i < len; i += 4)
{
EndianSwap(pData,i,4);
}
cout << endl;
cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.ID << endl;
cout << uppercase << hex << "改变字节序后: 0x" <<setfill('0') << setw(8) << wp.ID <<endl;
cout << endl;
cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.Num << endl;
cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.Num << endl;
cout << endl;
cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.Type << endl;
cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.Type << endl;
cout << endl;
cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.lat << endl;
cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.lat << endl;
cout << endl;
cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.lng << endl;
cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.lng << endl;
cout << endl;
cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.alt << endl;
cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.alt << endl;
cout << endl;
cout << uppercase << hex << "改变字节序前: 0x" << setfill('0') << setw(8) << wp_ori.speed << endl;
cout << uppercase << hex << "改变字节序后: 0x" << setfill('0') << setw(8) << wp.speed << endl;
return 0;
}
void EndianSwap(uint8 *pData, int startIndex, int length)
{
int i,cnt,end,start;
cnt = length / 2;
start = startIndex;
end = startIndex + length - 1;
uint8 tmp;
for (i = 0; i < cnt; i++)
{
tmp = pData[start+i];
pData[start+i] = pData[end-i];
pData[end-i] = tmp;
}
}
运行结果如下:
二、C/C++语言,对MSB、LSB的读/取处理 转自:https://blog.csdn.net/dijkstar/article/details/48765843
1. 做硬件的都知道,串口是LSB优先,I2C、1553B是MSB优先,这里的MSB、LSB指的是二进制位的位置,区别于【字节序】(通信中,先发送低字节,还是高字节的问题,那叫大端big-endian、小端little-endian)
如果需要自己来实现MSB、LSB的读取、转换,如何实现呢?下面给出C/C++程序:
#include "stdio.h" #define BITS_WIDTH (8) void main() { int val = 0; int i=0; // //接收:MSB在最左边,先进来 // for (i=0; i<BITS_WIDTH; i++) { val<<=1; if(i==0 || i==7)//模拟第N位上有高位 val++; } printf("接收MSB在最左边1,0x%x\n", val); // //接收:MSB在最左边,先进来 // val = 0; for (i=0; i<BITS_WIDTH; i++) { if(i==0 || i==2)//模拟第N位上有高位 { val |=1<<(BITS_WIDTH-1-i); } } printf("接收MSB在最左边2,0x%x\n", val); // //接收:LSB在最左边,先进来 // val = 0; for (i=0; i<BITS_WIDTH; i++) { //模拟第N位上有高位 if(i==0 || i==1) { val |=1<<i; } } printf("接收LSB在最左边,0x%x\n", val); printf("\n"); // //发送: 先发送高位,后发送低位 // val= 0x25; printf("发送数值0x%x按先高位后低位顺序: ", val); for (i=0; i<BITS_WIDTH; i++) { if ((val&0x80) == 0) printf("0, "); else printf("1, "); val <<=1; } printf("\n"); // //发送: 先发送低位,后发送高位 // val= 0x25; printf("发送数值0x%x按先低位后高位顺序: ", val); for (i=0; i<BITS_WIDTH; i++) { if ((val&0x01) == 0) printf("0, "); else printf("1, "); val >>=1; } printf("\n"); }
2. 字节序的大端、小端: x86系统用的是小端(little-endian),简单说:就是“先存储低字节,后存储高字节”,或者说“先低后高”
例如:unsigned int xyz = 0x0A0B0C0D;
内存中,先存储的0x0D, 0x0C, 0x0B,......,就是上面说的“先低后高”