从大端小端,到联合体与结构体

问题引出: 计算机大端小端之争。
1)Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
数字0x12345678 在大端小端的存储方式 

1)大端模式:

低地址 -----------------> 高地址
0x12  |  0x34  |  0x56  |  0x78

2)小端模式:

低地址 ------------------> 高地址
0x78  |  0x56  |  0x34  |  0x12

内存地址 小端模式存放内容 大端模式存放内容
0x4000 0x78 0x12
0x4001 0x56 0x34
0x4002 0x34 0x56
0x4003 0x12 0x78
大端小端的Pro and con
小端: 强制类型转化时候比较方便; 大端判断符号类型比较方便。

实际中: 
操作系统使用小端,网络程序使用大端;

硬件
Big endian: PowerPC, Sun, IBM;
Little endian: Intel, DEC
ARM既可以大端也可以小端。

如何判断是大端还是小端
void Test_1()
{
    unsigned int a = 0x1234; /*unsigned int to check if 0x 12 34 or 0x 34 12*/
    char* b = (char *) &a;   /*取unsigned int的地址,然后将它强制转化为char型*/

    if(b == 0x12)  /*如果是0x 12 34大端,强制转化了则b 为0x12*/
    {
        printf("Big endian\n");
    }else  /*如果是0x 34 12小端,强制转化了则b 为0x34*/
    {
        printf("Little endian and %x\n", *b);
    }
}

其他办法,因为C语言的联合的各个成员会共享一块内存,所以是否可以通过联合体来判断。
typedef unsigned char BYTE;
void Test_2()
{
    unsigned int num = 0; /*num = 0x 00 00 00 00*/
    unsigned int *p = #

    *(BYTE *)p = 0xff; /*to check where the system put the 0x 00 00 00 ff or 0x ff 00 00 00*/

    if(num == 0xff) /* 0x 00 00 00 ff*/
    {
        printf("This endian of cpu is little\n");
    }else           /* 0x ff 00 00 00*/
    {
        printf("This endian of cpu is big\n");
    }
}

看看linux 如何判断大端小端的
static union
{
    char c[4];
    unsigned long l;

}linuxEndianTest = {{'l','?','?','b'}};
#define LINUXENDIAN ((char) linuxEndianTest.l)
void Test_4()
{
    printf("%c", LINUXENDIAN);

}

实际的应用:
在单片机编程中,联合体和位域结合,可以实现对LED的控制
有时候既想操作整个字节 显示一个数,也想控制某位闪烁。
定义如下的联合体
typedef union uFLG{
    uint8 Flg ;                   //定义整型,可以一次性操作
    struct FLAG{               //位域定义,可以一次性操作一个位
        uint8   Flg1   : 1;
        uint8   Flg2   : 1;
        uint8   Flg3   : 1;
        uint8   Flg4   : 1;
        uint8   Flg5   : 1;
        uint8   Flg6   : 1;
        uint8   Flg7   : 1;
        uint8   Flg8   : 1;
    }tFlg;  
}uFlg;

//-------uF1-------------------
#define uFg1                uF1.Flg      //可以操作位
#define F_LED1          uF1.tFlg.Flg1
#define F_LED2          uF1.tFlg.Flg2
#define F_LED3          uF1.tFlg.Flg3

uFg1 = 0x88;
F_LED1 = 0x01;

网络协议中,不同的报文类型PackageType,不同的报文内容PackageContent,使用同一个结构表示。
typedef union tagPackageContent
 {
          PackageContent1 content1;
          PackageContent2 content2;
          PackageContent3 content3;
          PackageContent3 content3;
 };

typedef struct PackageStructure {
     Byte type;
     tagPackageContent content;
}



### 使用联合体结构体实现字节逆序的操作 在 C/C++ 中,联合体(`union`)和结构体(`struct`)可以结合使用来实现字节顺序的反转。联合体的特点是其所有成员共享同一块内存空间,而结构体则允许定义多个具有不同类型的成员变量[^1]。通过联合体结构体的组合,可以轻松访问数据的不同字节部分并进行操作。 以下是一个完整的代码示例,展示如何使用联合体结构体实现字节顺序的反转: ```c #include <stdio.h> #include <stdint.h> // 定义一个联合体,包含整数和结构体 union ByteSwapper { uint32_t value; // 用于存储原始值 struct { uint8_t byte0; // 最低位字节 uint8_t byte1; uint8_t byte2; uint8_t byte3; // 最高位字节 } bytes; // 结构体用于分别访问每个字节 }; // 字节逆序函数 uint32_t reverseBytes(uint32_t input) { union ByteSwapper swapper; swapper.value = input; // 将输入值赋给联合体的整数部分 // 手动交换字节顺序 uint32_t reversed = ( (swapper.bytes.byte3 << 24) | (swapper.bytes.byte2 << 16) | (swapper.bytes.byte1 << 8) | (swapper.bytes.byte0) ); return reversed; } int main() { uint32_t original = 0x12345678; // 原始值 uint32_t reversed = reverseBytes(original); // 调用字节逆序函数 printf("Original: 0x%08X\n", original); printf("Reversed: 0x%08X\n", reversed); return 0; } ``` #### 代码解析 1. **联合体定义**:联合体 `ByteSwapper` 包含一个 `uint32_t` 类型的成员 `value` 和一个结构体成员 `bytes`。结构体 `bytes` 分别定义了四个字节成员,用于访问 `value` 的每个字节[^1]。 2. **字节逆序逻辑**:通过将联合体的 `value` 成员赋值为输入值,可以直接访问其字节部分。然后通过位移运算符将字节重新排列,从而实现字节顺序的反转[^2]。 3. **测试输出**:在 `main` 函数中,定义了一个测试值 `0x12345678`,调用 `reverseBytes` 函数后打印结果以验证字节顺序是否正确反转。 #### 注意事项 - 在实际应用中,字节顺序的反转通常目标平台的序(大端或小)相关。如果需要处理跨平台问题,必须明确数据的存储格式[^3]。 - 如果需要对更大的数据类型(如 `uint64_t`)进行字节逆序,可以扩展联合体结构体的定义,增加更多的字节成员。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值