gpt4 book ai didi

c++ - 如何编写完全可移植的 4 字节字符常量的编译时初始化

转载 作者:太空狗 更新时间:2023-10-29 20:04:07 25 4
gpt4 key购买 nike

(遗留)代码大致如下所示。

#define MAKEID(a,b,c,d) (((UInt32)a)<<24 | ((UInt32)b)<<16 
| ((UInt32)c)<<8 | ((UInt32)d) )
#define ID_FORM MAKEID('F','O','R','M')
//...
struct S {
int id;
int x;
double d;
// other stuff
};
//...
S s;
socket.read(&s, sizeof(s)); // read network data over struct
if (s.id == ID_FORM) { }

代码将字符流读取到结构中。众所周知,S.id 是一个 4 字符常量,例如流(网络)顺序中的“FORM”或“DATA”,它决定了结构其余部分的布局。所有比较都是使用预定义常量的整数。

MAKEID 宏是大端法,因为它将第一个(字符)参数放在最高有效字节,这也是最低内存地址。小端版本的宏看起来像这样,将第一个(字符)参数放在最低有效字节,现在是最低内存地址。

 #define MAKEID(a,b,c,d) (((UInt32)d)<<24 | ((UInt32)c)<<16 
| ((UInt32)b)<<8 | ((UInt32)a) )

问题是如何重写它以使其在大端和小端架构上同样有效。

不,我不想写两个宏并选择带有#ifdef 的宏。代码中的任何地方都没有其他字节序依赖项,我不想在这里介绍。可移植是必经之路。

不,我不想写函数。这个常量用在函数不能去的地方。我编写了一个初始化 union 的可移植函数,但代码无法编译。

我正在寻找任何类型的可移植宏或模板来进行编译时初始化。

在回答评论时,这是真正的代码。它是网络协议(protocol)的一部分,在大多数情况下,另一端负责字节顺序。这恰好是一个异常(exception),另一端以网络字节顺序生成,而这一端在历史上被写成 big-endian 作为 4 字节字符常量,如“FORM”。我需要一个单点解决方案,而不是将字节顺序的想法传播到代码中其他地方的解决方案。

最佳答案

您的 MAKEID 宏与字节顺序无关。它在大端和小端系统上的工作方式相同。

宏可能看起来是大端特定的,但 C++ 中的移位和按位或操作都是根据它们对操作的值的结果定义的,而不是这些值的底层存储。< br/>执行 42 << 24 保证将值 42 放在结果的最高有效 8 位中,而不管字节顺序如何。与按位或操作类似。这意味着无论底层存储的字节顺序如何,MAKEID(0x12, 0x34, 0x56, 0x78) 的结果始终是 0x12345678

如果您想生成一个整数,其底层存储始终具有相同的位模式(例如,0x12、0x34、0x56、0x78),那么您真的必须重新考虑您的方法。这样的整数在大端系统上的值为 0x12345678,在小端系统上为 0x78563412,在中端系统上可能为 0x56781234
但是,如果通过使用特定字节顺序(例如大端/网络字节顺序)定义的通信接口(interface)接收到该位模式,则必须将接收到的任何多字节值转换为系统的 native 字节如果您希望接收系统正确解释这些值并且包括四字节 ID 值,请订购。

这就是为什么我在早期版本的答案中说过,如果您发现在某些系统上(特别是那些系统的字节顺序与通信的字节顺序不匹配的系统),从流中读取的 ID 不会匹配 MAKEID 的结果,那么可能的罪魁祸首是反序列化代码。 (反)序列化代码是考虑字节序的最重要的地方。例如,将您期望的结构覆盖在您收到的字节上很容易,但如果可能存在字节顺序不匹配或填充差异,这就是错误的解决方案。

关于c++ - 如何编写完全可移植的 4 字节字符常量的编译时初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22239629/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com