字节序的支持:大端和小端

6
我们需要支持3种硬件平台 - Windows (little Endian) 和 Linux Embedded (big and little Endian)。我们的数据流取决于所使用的机器,数据需要分解为位域。
如果可能的话,我想编写一个单一的宏来抽象细节。在Linux上,我可以使用 bswap_16 / bswap_32 / bswap_64 进行 Little Endian 转换。
然而,在我的 Visual C++ includes 中找不到这个函数。
是否有通用的内置函数可用于这两个平台(Windows 和 Linux)?
如果没有,那么在 Visual C++ 中可以使用什么来进行字节交换(除了自己编写 - 希望有一些机器优化的内置函数)?
谢谢。
3个回答

13
在这两个平台上,您都可以使用以下内容:
对于short(16位):htons()ntohs() 对于long(32位):htonl()ntohl() 缺失的htonll()ntohll()用于long long(64位)可以轻松从这两个函数构建。例如,请参见此实现更新-0: 如链接示例中的Simon Richter在评论中提到,它不一定能正常工作。原因是:编译器可能在使用的联合体中引入额外的字节。为了解决此问题,需要打包这些联合体。后者可能会导致性能下降。
因此,以下是另一种故障安全方法来构建*ll函数:https://dev59.com/BnRA5IYBdhLWcg3w0xnk#955980 更新-0.1: 根据bames53的评论,我倾向于认为上述第一个示例不应与C ++一起使用,而应仅与C一起使用。 更新-1: 要在Linux上实现*ll函数的功能,此方法可能是“最佳”的

请注意,他们使用 union 的示例实现无法保证正常工作。 - Simon Richter
是的,你说得对,联合体应该被打包。感谢你指出这一点。请查看我回答的更新。@SimonRichter - alk
使用联合体的问题不仅仅是打包。在C++中,像这样使用联合体是未定义的行为;优化器可以合法地将 union { int x, y; } u; u.x = 5; return u.y; 转换为 return 0;,例如。 - bames53
1
[class.union] 9.5/1,或者在这个问题中有更详细的解释。 - bames53
实际上,这里有一个更好的:https://dev59.com/9mgu5IYBdhLWcg3wYF-3 - bames53
显示剩余2条评论

2

死链,你能列出名称吗? - Grant Rostig
1
@GrantRostig - 已编辑答案并提供了一个存档链接。 - user93353
1
新链接:https://learn.microsoft.com/zh-cn/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort?view=vs-2019 - phuclv

2

如果您坚持处理字节序,htons和htonl(以及类似的宏)是不错的选择。

然而,更好的方法是通过输出ASCII或类似格式来避免这个问题。虽然需要更多的空间,传输速度也会稍微慢一些,但简单性和未来性是值得的。

另一个选择是将int和short数值进行数字分解。所以您可以使用“& 0xff”并重复除以256。这样可以在所有体系结构上获得单一格式。但是,使用ASCII仍然更容易进行调试。


很想这样做,但我们无法控制传输。它是从特殊的硬件设备中读取的数据,并需要处理那里的字节。 - user626201

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接