通过互联网发送布尔值(Windows 和 Linux)
我使用打包结构将信息从服务器发送到客户端,然后再次返回(显然结构中还有更多数据),
#pragma pack(push, 1)
struct other_data_struct
{
int hp;
int wp;
char movetype;
}
struct PlayerStats
{
int playerID;
other_data_struct data;
bool friendly; //<-this one messes up how the others are going to be packed on the 2 systems
}
#pragma pack(pop)
这对于所有固定大小的变量、整数和字符甚至其他结构都适用。
尽管当服务器使用 Linux 的 gcc 编译并且客户端使用 Windows 的 MSVC 编译时,布尔值不能很好地工作......
我想过制作某种容器(即带有 8 个布尔值 get/set 的无符号字符)函数或类似),但它看起来既古怪又不优雅。
有没有某种方法可以在 Windows 和 Linux 上“打包”包含完全相同的布尔变量的结构,或者我应该咬酸苹果并为每个布尔值使用 char ?
I'm sending information from my server to clients and back again using packed structs (obviously there are a lot more data in the structs)
#pragma pack(push, 1)
struct other_data_struct
{
int hp;
int wp;
char movetype;
}
struct PlayerStats
{
int playerID;
other_data_struct data;
bool friendly; //<-this one messes up how the others are going to be packed on the 2 systems
}
#pragma pack(pop)
That works fine for all fixed sized variables, ints and chars and even other structs.
The boolean doesn't work well though when the server is compiled with gcc for Linux and the client is compiled with MSVC for windows...
I have thought of making some sort of container (ie. a unsigned char with 8 boolean get/set functions or similar) but it seems as quirky as inelegant.
Is there some way to 'pack' structs containing boolean variables exactly the same on Windows and Linux or should I bite the sour apple and use a char for each boolean?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
每当您在不同系统之间传输数据时,您不应该依赖这些系统如何在内存中表示数据,因为内存表示可能会因处理器体系结构、编译器选项和许多其他因素而异。您应该使用某个库进行序列化,因为该库的作者已经对您可能不感兴趣的各种问题投入了很多想法。
Whenever you transfer data between different systems, you should not rely on how these systems represent the data in memory, because the memory representation may vary with the processor architecture, the compiler options, and many other things. You should use some library for serialization instead, since the authors of that library have already put many thoughts into all kinds of problems that you are probably not interested in.
您可以使用 Google Protocol Buffers 而不是您自己的打包结构。或者您可以避开 bool 以避免不兼容。
如果我真的必须从你所在的位置开始并使其工作,我会用其中的结构编写一个小程序,并开始尝试使用额外的填充字段,直到我想出一些在两个系统上看起来完全相同的东西。
You could use Google Protocol Buffers instead of your own packed structures. Or you could eschew bool to avoid the incompatibility.
If I really had to start from where you are and make it work, I'd make a little program with the structs in it and start experimenting with additional padding fields until I came up with something that looked precisely the same on the two systems.
在一般情况下,您不应该对字节顺序、字段大小、结构打包等做出假设。对于一般应用程序或库开发,这样做是不好的做法。
也就是说,在嵌入式系统上工作时,我经常做这种事情,其中 1) 内存(RAM 和可执行 ROM)是宝贵的资源,因此需要避免不必要的库,2) 我知道我的代码只会针对一个平台,3) 不想承受打包/拆包的性能损失。即使如此,这也可能不是“最佳”做法。
如果您意识到这样做的风险,我想您自己已经回答了这个问题。如果您想 100% 确定,请为布尔值定义您自己的类型。另请注意,
long
的大小在 32 位和 64 位平台之间有所不同。我通常坚持对每个数字基元使用“stdint.h”类型,这样你就知道你正在处理的大小。In the general case, you should not make assumptions about endianess, size of fields, structure packing etc. For general application or library development, it would be bad practice to do this kind of thing.
That said, I do this kind of thing fairly often when working on embedded systems where 1) memory (both RAM & executable ROM) is a precious resource, so unnecessary libraries need to be avoided and 2) I know my code will only target one platform, and 3) don't want to take the performance hit of packing/unpacking. Even then, it's probably not a 'best' practice.
If you are aware of the risks of doing things this way, I think you answered this one yourself. Define your own type for the boolean if you want to be 100% sure. Also beware that the size of
long
differs between a 32-bit and 64-bit platform. I usually stick with "stdint.h" types for every numeric primitive, that way you know what size you're dealing with.您可以尝试 bitfields,这样您的打包结构包含 'int ',但是您的代码使用了更节省空间的表示形式。
我相信位域有一些糟糕的性能特征,所以如果您更关心访问时间而不是空间使用,那么它们可能不是正确的选择。
You could try bitfields, that way your packed struct contains 'int', but your code uses a more space-efficient representation.
I believe bitfields have some awful performance characteristics, so they may not be the way to go if you care more about access time than space usage.
为什么不在调用 ntohl、htonl、ntohs、htons 等时进行序列化。这将很好地转换字节序 - 而且比您正在做的更安全。如果您使用结构,那么您必须更多地担心与编译器相关的事情,而不是使用已知大小的核心类型。
这些函数将数据按照网络字节顺序排列,这是通信设备之间网络传输的标准。其他网络程序员也会更好地理解您的代码以进行维护:)
Why don't you just serialize while calling ntohl, htonl, ntohs, htons, etc. This will convert the endian-ness fine - and it's a little safer than what you're doing. You have to worry more about compiler dependent things if you're using structs than if you're using core types of known sizes.
The functions put data in network byte order which is the standard for network transport between communicating devices. Other network programmers will understand your code better too for maintenance purposes :)
我不清楚问题是什么。 Windows 和 Linux 都将
bool
定义为一字节对象。Windows确实将
BOOL
定义为int
,因此如果您将BOOL
放在电线上并读取它作为一个bool
(或者将一个bool
放在电线上并将其读取为BOOL
),那么你就会遇到麻烦。这相对容易修复。Windows 和 Linux 可能为
false
和true
定义了不同的值(更有可能的是,他们同意false
是0
code>,但不同意true
使用的值;即使在网络编程之外,也可能存在非true< 的
bool
变量/code> 或false
,见下文)。该标准要求bool
至少为一个字节,并且一个字节具有远远超过两个可能的值。是的,将您的
bool
转换为unsigned char
并通过线路发送该就可以正常工作。注意:“
bool
变量不是true
或false
”:I'm not clear on what the problem would be. Both Windows and Linux define
bool
as a one-byte object.Windows does define
BOOL
as anint
, so if you're putting aBOOL
on the wire and reading it as abool
(or putting abool
on the wire and reading it as aBOOL
) then you're going to have trouble. That's relatively easy to fix.It may be that Windows and Linux define different values for
false
andtrue
(more likely, they agree thatfalse
is0
, but don't agree on the value used fortrue
; even outside of network programming it's possible to havebool
variables that are aren'ttrue
orfalse
, see below). The Standard requires thatbool
s be at least one byte, and a byte has far more than two possible values.Yes, converting your
bool
s tounsigned char
s and sending that over the wire will work fine.Note: "
bool
variables that are aren'ttrue
orfalse
":