将任何变量从大端转换为小端 - 如何避免空指针?

Posted

技术标签:

【中文标题】将任何变量从大端转换为小端 - 如何避免空指针?【英文标题】:Converting any variable from big to little endian - how to avoid void pointers? 【发布时间】:2022-01-18 18:13:41 【问题描述】:

我正在开发一个需要将任何类型的变量从大端转换为小端的应用程序。

我的系统使用不同的变量类型(16、32 和 64 位宽),我需要能够使用单个函数更改字节顺序。我编写了一个函数,可以设法交换任何变量中的字节,但是我对此并不满意。它可以工作,但它需要取消引用 void 指针,这很容易与双星出现错误......

    有没有更好的方法来解决这个问题? 有什么方法可以避免 void 指针作为返回值?我在考虑 switch-case 循环(例如 case 4 bytes -> return int32)但是,我不知道如何为返回不同值的函数编写函数原型。

我的功能:

void* swapBytes(void* number, int bytes_num)
    void* swapped;
    unsigned __int8* single_byte_ptr;
    swapped = malloc(bytes_num * sizeof(__int8));

    for (int i = 0; i<bytes_num; i++)
        single_byte_ptr =((unsigned __int8*)number)+i; //get current byte
        *( (__int8*)(swapped)+((bytes_num-1)-i)) = (unsigned __int8)*single_byte_ptr; //save the byte in new position
    

    return swapped;


我调用这个函数的方式

__int64 big_number = 35169804487071;
big_number = *(__int64*)(swapBytes(&big_number, 8));

【问题讨论】:

我的系统使用不同的变量类型... - 您的系统如何获取“错误”格式的数据? 我正在研究 MPC5748G - 来自 NXP 的微控制器 - 我正在从 CAN 读取数据,CAN 与许多其他设备连接到总线。这些设备使用不同的数据格式。 你的代码也会泄露内存。 那么最便携的方法是将输入作为字节流并“手动”重新解释(如word = byte0 + (byte1 &lt;&lt; 8) + (byte2 &lt;&lt; 16) +... 对this question的回答有很多建议。 【参考方案1】:

您遇到的一个问题是内存泄漏。您返回一个指向 malloc 内存的指针,但是当您返回时您并没有保存指针。

鉴于您将结果分配回相同的值,您最好更新现有变量,将当前字节与“相反”侧的字节交换。

您也不需要在参数类型以外的任何地方使用void *。在函数内部,只需使用指向 unsigned charunsigned __int8 的指针来处理字节。

void swapBytes(void* number, int bytes_num)

    unsigned __int8* ptr = number;
    for (int i = 0; i<bytes_num/2; i++) 
        unsigned __int8 tmp = ptr[i];
        ptr[i] = ptr[bytes_num-1-i];
        ptr[bytes_num-1-i] = tmp;
    

然后这样称呼它:

swapBytes(&big_number, sizeof(big_number));

【讨论】:

考虑使用size_t 而不是int【参考方案2】:

您的解决方案设计过度,也完全不适合 MPC57xx 等嵌入式系统。

使用指向字符的指针可以安全地遍历任何整数类型。假设uint8_t* 是编译器的字符类型,就这么简单:

void little_to_big16 (uint8_t       big    [sizeof(uint16_t)], 
                      const uint8_t little [sizeof(uint16_t)])

  big[0] = little[1];
  big[1] = little[0];

然后根据需要编写big_to_little16big_to_little32 等。这样的函数也可以也应该被内联。

使用示例:

#include <stdio.h>
#include <inttypes.h>

void little_to_big16 (uint8_t       big    [sizeof(uint16_t)], 
                      const uint8_t little [sizeof(uint16_t)])

    big[0] = little[1];
    big[1] = little[0];


int main (void)

  uint16_t little = 0xAABB;
  uint16_t big;
  little_to_big16((uint8_t*)&big, (uint8_t*)&little);
  printf("%"PRIx16, big);

x86 little endian 上的输出:

bbaa

【讨论】:

以上是关于将任何变量从大端转换为小端 - 如何避免空指针?的主要内容,如果未能解决你的问题,请参考以下文章

从二进制文件读取时将大端转换为小端

将大端转换为小端的 C/C++ 代码

内存对齐 大端字节,序小端字节序验证

关于摩托罗拉的can协议(处理器为大端,协议为小端)

大端小端存储模式

flutter大端小端转换