有没有办法为C或C++结构强制执行特定的字节序?

vsz*_*vsz 25 c c++ endianness low-level

我已经看到了关于结构的字节序的一些问题和答案,但它们是关于检测系统的字节序,或者在两个不同的字节序之间转换数据.

但是,如果有一种方法可以强制执行给定结构的特定字节顺序,那么我现在想要的是什么.是否有一些好的编译器指令或其他简单的解决方案,除了重写操作在位域上的很多宏的整个事情?

一般的解决方案会很好,但我也会对特定的gcc解决方案感到满意.

编辑:

感谢所有评论指出为什么强制执行endianness不是一个好主意,但在我的情况下,这正是我需要的.

特定处理器生成大量数据(永远不会改变,它是带有自定义硬件的嵌入式系统),并且必须由在未知处理器上运行的程序(我正在处理)读取.对数据进行字节评估会非常麻烦,因为它包含数百种不同类型的结构,这些结构非常庞大且深入:它们中的大多数都有许多其他巨大的结构层.

改变嵌入式处理器的软件是不可能的.源是可用的,这就是为什么我打算使用该系统的结构而不是从头开始并按字节方式评估所有数据.

这就是为什么我需要告诉编译器它应该使用哪个字节序,无论效率与否都无关紧要.

它不一定是字节序的真正变化.即使它只是一个接口,物理上所有东西都是在处理器自己的字节序中处理的,但我完全可以接受.

Nem*_*emo 20

我通常处理这个的方式是这样的:

#include <arpa/inet.h> // for ntohs() etc.
#include <stdint.h>

class be_uint16_t {
public:
        be_uint16_t() : be_val_(0) {
        }
        // Transparently cast from uint16_t
        be_uint16_t(const uint16_t &val) : be_val_(htons(val)) {
        }
        // Transparently cast to uint16_t
        operator uint16_t() const {
                return ntohs(be_val_);
        }
private:
        uint16_t be_val_;
} __attribute__((packed));
Run Code Online (Sandbox Code Playgroud)

同样的be_uint32_t.

然后你可以像这样定义你的结构:

struct be_fixed64_t {
    be_uint32_t int_part;
    be_uint32_t frac_part;
} __attribute__((packed));
Run Code Online (Sandbox Code Playgroud)

关键是编译器几乎肯定按照你编写它们的顺序排列字段,所以你真正担心的是big-endian整数.该be_uint16_t对象是一个知道如何根据需要在big-endian和machine-endian之间透明地转换自身的类.像这样:

be_uint16_t x = 12;
x = x + 1; // Yes, this actually works
write(fd, &x, sizeof(x)); // writes 13 to file in big-endian form
Run Code Online (Sandbox Code Playgroud)

实际上,如果使用任何相当不错的C++编译器编译该代码片段,您应该会发现它会将大端"13"作为常量发出.

使用这些对象,内存中表示是big-endian.所以你可以创建它们的数组,把它们放在结构中等等.但是当你去操作它们时,它们会神奇地投射到机器端.这通常是x86上的单个指令,因此非常有效.有一些情况需要手工施放:

be_uint16_t x = 37;
printf("x == %u\n", (unsigned)x); // Fails to compile without the cast
Run Code Online (Sandbox Code Playgroud)

...但是对于大多数代码,您可以像使用内置类型一样使用它们.

  • 我唯一的建议是考虑将它声明为结构而不是类.由于您明确指定了所有成员的可访问性,因此两者正式相当.然而,结构具有轻量级的内涵,这绝对是be_uint32_t的目标.它还有一些通常由值而不是通过引用或指针使用的内涵,be_uint32_t也是如此.另一方面,be_uint32_t没有公共字段,这也是struct的含义. (2认同)

Nik*_*lle 12

派对有点晚了,但是使用当前的GCC(在6.2.1上测试了它的工作原理和4.9.2在未实现的情况下测试),最后有一种方法可以声明结构应该保持X端字节顺序.

以下测试程序:

#include <stdio.h>
#include <stdint.h>

struct __attribute__((packed, scalar_storage_order("big-endian"))) mystruct {
    uint16_t a;
    uint32_t b;
    uint64_t c;
};


int main(int argc, char** argv) {
    struct mystruct bar = {.a = 0xaabb, .b = 0xff0000aa, .c = 0xabcdefaabbccddee};

    FILE *f = fopen("out.bin", "wb");
    size_t written = fwrite(&bar, sizeof(struct mystruct), 1, f);
    fclose(f);
}
Run Code Online (Sandbox Code Playgroud)

创建一个文件"out.bin",您可以使用十六进制编辑器(例如hexdump -C out.bin)进行检查.如果支持scalar_storage_order属性,它将按此顺序包含预期的0xaabbff0000aaabcdefaabbccddee且没有漏洞.遗憾的是,这当然是特定于编译器的.