3


我必须在道具上工作。二进制文件格式,想用结构体来实现。
我的结构中需要恒定的字节序列,而 atm 我不知道如何实现这一点。

我想过这样的事情:

#include <cstdint>
#pragma pack(push,1)

typedef struct PAYLOAD_INFO {
    const uint8_t magicnumber[4] =  { 0xFA, 0x11 , 0x28 , 0x33 };
    uint16_t UMID;
    const uint16_t VID = 1487 ;
    uint32_t crc;
};

#pragma pack(pop)

int main (){
  PAYLOAD_INFO pldInst;
  pldInst.UMID = 5;
  pldInst.crc = 0x34235a54;
  ...
  writeToFile(&PAYLOAD_INFO,sizeof(PAYLOAD_INFO));
}

最后“pldInst”应该看起来像那样(在内存中),而不考虑本示例中的字节顺序:

0x00000000:  0xFA, 0x11 , 0x28 , 0x33
0x00000004:  0x00, 0x05 , 0x05 , 0xCF
0x00000008:  0x34, 0x23 , 0x5a , 0x54

我已经尝试过“默认”方法:

#include <cstdint>
#pragma pack(push,1)

typedef struct PAYLOAD_INFO {
    static const uint8_t magicnumber[4];
    uint16_t UMID;
    static const uint16_t VID = 1487 ;
    uint32_t crc;
};

const uint8_t magicnumber[4] =  { 0xFA, 0x11 , 0x28 , 0x33 };

#pragma pack(pop)

但没有按预期工作。

有没有办法在不计算每个结构成员的内存大小、分配新内存和复制每个成员的情况下完成这项工作?

我使用 g++ 4.6.3。

问候,托马斯

更新:
@bikeshedder 提供的 c++11 解决方案运行良好,但只能使用 g++ 4.7 或更高版本进行编译。

4

2 回答 2

4

您的静态当前只是定义一个全局静态。您需要添加一个类说明符来将静态定义为您的类的一部分。

const uint8_t PAYLOAD_INFO::magicnumber[4] = { 0xFA, 0x11 , 0x28 , 0x33 };

也就是说,正如@bikeshedder 下面提到的那样,静态数据单独存储在内存中,因此当您创建结构的新实例时,该实例不会在实例的内存位置包含幻数,因此您的使用writeToFile不会像您一样工作预计。

于 2013-02-02T02:16:01.563 回答
3

我建议不要对structs原始内存进行任何类型的转换,除非您使用的内核接口可以保证在同一台机器上运行并且应该以这种方式使用。

这不是可移植的(字节序问题),每个编译器的做法都有点不同,性能也没有好多少。总而言之,它不能证明这种不良做法是正当的。

您的代码示例不起作用的原因是静态成员。由于静态成员不仅是对象(而是类)的一部分,而且UMID是以crc这种方式编写的。

struct PAYLOAD_INFO {
    const uint8_t magicnumber[4] = { 0xFA, 0x11, 0x28, 0x33 };
    uint16_t UMID;
    const uint16_t VID = 1487 ;
    uint32_t crc;
};

此代码仅适用于 C++11,但由于您包含cstdint我假设您已经使用该 C++ 版本。如果您不使用 C++11,则需要在构造函数中初始化成员,并且不能使用const幻数,因为它无法初始化。(请参阅:在 C++ 中的类初始化程序中初始化 const 数组

struct PAYLOAD_INFO {
    const uint8_t magicnumber[4] = { 0xFA, 0x11, 0x28, 0x33 };
    uint16_t UMID;
    const uint16_t VID = 1487 ;
    uint32_t crc;
};

对于 C++98,您需要执行以下操作:

struct PAYLOAD_INFO {
    uint8_t magicnumber[4];
    uint16_t UMID;
    const uint16_t VID;
    uint32_t crc;
    PAYLOAD_INFO() : VID(1487)
    {
        magicnumber[0] = 0xFA;
        magicnumber[1] = 0x11;
        magicnumber[2] = 0x28;
        magicnumber[3] = 0x33;
    }
};
于 2013-02-02T02:20:46.743 回答