c++ - 正确处理字节对齐问题 -- 16位嵌入式系统和32位桌面通过UDP

标签 c++ c casting embedded

我正在处理的应用程序从一个嵌入系统接收 C 风格的结构,该嵌入系统的代码是为 16 位处理器生成的。与嵌入式系统对话的应用程序是使用 32 位 gcc 编译器或 32 位 MSVC c++ 编译器构建的。应用程序和嵌入式系统之间的通信通过以太网或调制解调器上的 UDP 数据包进行。

UDP 数据包中的有效载荷由各种不同的 C 风格结构组成。在应用程序端,C++ 风格的 reinterpret_cast 能够获取无符号字节数组并将其转换为适当的结构。

但是,当结构包含枚举值时,我遇到了 reinterpret_cast 问题。 16 位 Watcom 编译器会将枚举值视为 uint8_t 类型。但是,在应用程序端,枚举值被视为 32 位值。当我收到一个包含枚举值的数据包时,数据会出现乱码,因为应用程序端的结构比嵌入式端的结构大。

到目前为止,这个问题的解决方案是将应用程序端结构中的枚举类型更改为 uint8_t。但是,这不是最佳解决方案,因为我们不能再将成员用作枚举类型。

我正在寻找的是一种解决方案,它允许我使用简单的强制转换操作,而不必在应用程序端篡改源代码中的结构定义。通过这样做,我可以在我的应用程序的上层使用该结构。

最佳答案

如前所述,正确处理问题是正确的序列化和反序列化。

但这并不意味着我们不能尝试一些技巧。

选项 1: 如果您的特定编译器支持打包枚举(在我的例子中是 Windows 中的 gcc 4.7),这可能有效:

typedef enum { VALUE_1 = 1, VALUE_2, VALUE_3 }__attribute__ ((__packed__)) TheRealEnum;

选项 2:

如果您的特定编译器支持 < 4 字节的类大小,您可以使用 HackedEnum 类,该类使用运算符重载进行转换(请注意您可能不会使用的 gcc 属性想要它):

class HackedEnum
{
private:
    uint8_t evalue;
public:
    void operator=(const TheRealEnum v) { evalue = v; };
    operator TheRealEnum() { return (TheRealEnum)evalue; };
}__attribute__((packed));

您可以将结构中的 TheRealEnum 替换为 HackedEnum,但您仍然继续将其用作 TheRealEnum。

查看它工作的完整示例:

#include <iostream>
#include <stddef.h>

using namespace std;

#pragma pack(push, 1)

typedef enum { VALUE_1 = 1, VALUE_2, VALUE_3 } TheRealEnum;

typedef struct
{
    uint16_t v1;
    uint8_t enumValue;
    uint16_t v2;
}__attribute__((packed)) ShortStruct;

typedef struct
{
    uint16_t v1;
    TheRealEnum enumValue;
    uint16_t v2;
}__attribute__((packed)) LongStruct;

class HackedEnum
{
private:
    uint8_t evalue;
public:
    void operator=(const TheRealEnum v) { evalue = v; };
    operator TheRealEnum() { return (TheRealEnum)evalue; };
}__attribute__((packed));

typedef struct
{
    uint16_t v1;
    HackedEnum enumValue;
    uint16_t v2;
}__attribute__((packed)) HackedStruct;

#pragma pop()

int main(int argc, char **argv)
{
    cout << "Sizes: " << endl
         << "TheRealEnum: " << sizeof(TheRealEnum) << endl
         << "ShortStruct: " << sizeof(ShortStruct) << endl
         << "LongStruct: " << sizeof(LongStruct) << endl
         << "HackedStruct: " << sizeof(HackedStruct) << endl;

    ShortStruct ss;
    cout << "address of ss: " << &ss <<  " size " << sizeof(ss) <<endl
         << "address of ss.v1: " << (void*)&ss.v1 << endl
         << "address of ss.ev: " << (void*)&ss.enumValue << endl
         << "address of ss.v2: " << (void*)&ss.v2 << endl;

    LongStruct ls;
    cout << "address of ls: " << &ls <<  " size " << sizeof(ls) <<endl
         << "address of ls.v1: " << (void*)&ls.v1 << endl
         << "address of ls.ev: " << (void*)&ls.enumValue << endl
         << "address of ls.v2: " << (void*)&ls.v2 << endl;

    HackedStruct hs;
    cout << "address of hs: " << &hs <<  " size " << sizeof(hs) <<endl
         << "address of hs.v1: " << (void*)&hs.v1 << endl
         << "address of hs.ev: " << (void*)&hs.enumValue << endl
         << "address of hs.v2: " << (void*)&hs.v2 << endl;


    uint8_t buffer[512] = {0};

    ShortStruct * short_ptr = (ShortStruct*)buffer;
    LongStruct * long_ptr = (LongStruct*)buffer;
    HackedStruct * hacked_ptr = (HackedStruct*)buffer;

    short_ptr->v1 = 1;
    short_ptr->enumValue = VALUE_2;
    short_ptr->v2 = 3;

    cout << "Values of short: " << endl
            << "v1 = " << short_ptr->v1 << endl
            << "ev = " << (int)short_ptr->enumValue << endl
            << "v2 = " << short_ptr->v2 << endl;

    cout << "Values of long: " << endl
            << "v1 = " << long_ptr->v1 << endl
            << "ev = " << long_ptr->enumValue << endl
            << "v2 = " << long_ptr->v2 << endl;

    cout << "Values of hacked: " << endl
            << "v1 = " << hacked_ptr->v1 << endl
            << "ev = " << hacked_ptr->enumValue << endl
            << "v2 = " << hacked_ptr->v2 << endl;



    HackedStruct hs1, hs2;

    // hs1.enumValue = 1; // error, the value is not the wanted enum

    hs1.enumValue = VALUE_1;
    int a = hs1.enumValue;
    TheRealEnum b = hs1.enumValue;
    hs2.enumValue = hs1.enumValue;

    return 0;
}

我的特定系统的输出是:

Sizes:
TheRealEnum: 4
ShortStruct: 5
LongStruct: 8
HackedStruct: 5
address of ss: 0x22ff17 size 5
address of ss.v1: 0x22ff17
address of ss.ev: 0x22ff19
address of ss.v2: 0x22ff1a
address of ls: 0x22ff0f size 8
address of ls.v1: 0x22ff0f
address of ls.ev: 0x22ff11
address of ls.v2: 0x22ff15
address of hs: 0x22ff0a size 5
address of hs.v1: 0x22ff0a
address of hs.ev: 0x22ff0c
address of hs.v2: 0x22ff0d
Values of short:
v1 = 1
ev = 2
v2 = 3
Values of long:
v1 = 1
ev = 770
v2 = 0
Values of hacked:
v1 = 1
ev = 2
v2 = 3

关于c++ - 正确处理字节对齐问题 -- 16位嵌入式系统和32位桌面通过UDP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13097312/

相关文章:

c - AVR UART 读取单个字节两次

c - 有什么方法可以在 ANSI c 中创建大小为 32 的字符吗?

c++ - 将 union 转换为其成员类型之一

c++ - 是否可以在 C++ 中编写自定义转换运算符(如 `static_cast` )?

c - 三个数组的并集、交集和差集

c - 为什么这个定义宏要执行强制转换?

c++ - C++ 函数声明中,右括号前的 & 符号有何作用?

c++ - QtQuick、动态图像和 C++

c++ - 我在哪里可以获得 afx...h 文件?

c++ - 显式特化已经被实例化