大小端转换源码

文章目录

  • 背景
  • 大下端常规定义
  • 大小端转换示例

背景

在不同的计算机系统中,数据的存储和读取有所不同,计算机的通信和存储依赖于一致的规则。目前计算机通常采用的存储机制主要有两种:大端模式(Big-endian)和小端模式(Little-endian)

大下端常规定义

   大端模式:数据的低位或低字节(对整个序列取值影响最小的那个bit/byte)保存在内存的高地址中,而数据的高位或高字节,存储时放在低地址,读取时放在流开始。这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放,存储顺序与我们所看到的数据顺序一致;
  小端模式:数据的低位或低字节,存储时放在低地址,读取时放在流的末尾,而数据的高位或高字节保存在内存的高地址中。
  关于大小端更深刻更容易记忆的定义请见我的另外一篇博客:大小端如何理解记忆

大小端转换示例

   在通信中,读写寄存器地址及数据流有规定的大小端格式,需要按照规定的格式来通信。

#include 
#include 
#include 
#include 

#define BUF_LEN   ( 4 )
static void endian_exchange(uint8_t *buf, uint32_t len);
static void Fbytes_endian_exchange(uint32_t *buf, uint32_t len);  // four bytes endian exchange

static void endian_exchange(uint8_t *buf, uint32_t len) {
    uint32_t size = len & 0xFFFFFFFE;  // 长度取偶数操作
    uint32_t i = 0;
    uint8_t buf_tmp = 0;

	if (NULL == buf) {
		printf("[%s] buf = %p  len = %u", __func__, buf , len);
		return;
	}

	for (i = 0; i < size; i += 2) {
		buf_tmp = buf[i + 1];
		buf[i + 1] = buf[i];
		buf[i] = buf_tmp;
	}
}

static void Fbytes_endian_exchange(uint32_t *buf, uint32_t len) {
    uint32_t i = 0;
    if (NULL == buf || len < 3 || (0 != len % 4)) {
        printf("[%s] buf = %p  len = %u", __func__, buf , len);
        return;
    }

    for (i = 0; i < len / 4; i++) {
        buf[i] = ((buf[i] & 0x00FF00FF) << 8) | ((buf[i] >> 8) & 0x00FF00FF);
        buf[i] = ((buf[i] & 0x0000FFFF) << 16) | ((buf[i] >> 16) & 0x0000FFFF);
    }
}

int main(void) {
	uint8_t i = 0;
	uint8_t buf_8[BUF_LEN] = {0x01, 0x23, 0x45, 0x67};
	uint32_t buf_32 = 0x01234567;

    for (i = 0; i < BUF_LEN; i++) {
		printf("[%s] buf_8[%u] = 0x%02x \n", __func__, i, buf_8[i]);
	}
    printf("[%s] buf_32 = 0x%x \n", __func__, buf_32);

    endian_exchange(buf_8, BUF_LEN * sizeof(buf_8[0]));
    for (i = 0; i < BUF_LEN; i++) {
		printf("[%s] endian_exchange buf_8[%u] = 0x%02x \n", __func__, i, buf_8[i]);
	}

    Fbytes_endian_exchange(&buf_32, sizeof(buf_32));
    printf("[%s] Fbytes_endian_exchange buf_32 = 0x%x \n", __func__, buf_32);

    return 0;
}

   上述示例分别完成了16位和32位大小端转换(即2字节和4字节),结果如下:

[main] buf_8[0] = 0x01 
[main] buf_8[1] = 0x23 
[main] buf_8[2] = 0x45 
[main] buf_8[3] = 0x67 
[main] buf_32 = 0x1234567 
[main] endian_exchange buf_8[0] = 0x23 
[main] endian_exchange buf_8[1] = 0x01 
[main] endian_exchange buf_8[2] = 0x67 
[main] endian_exchange buf_8[3] = 0x45 
[main] Fbytes_endian_exchange buf_32 = 0x67452301  

   可以看出:

  • 16位大小端转换是将每16位数据的高低字节调换存储位置
  • 32位大小端转换是先将每16位数据的高低字节调换存储位置,再将每相邻的两个字节调换位置

你可能感兴趣的:(C语言,Linux)