通过互联网发送布尔值(Windows 和 Linux)

发布于 2024-12-08 01:22:41 字数 594 浏览 0 评论 0原文

我使用打包结构将信息从服务器发送到客户端,然后再次返回(显然结构中还有更多数据),

#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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

Oo萌小芽oO 2024-12-15 01:22:41

每当您在不同系统之间传输数据时,您不应该依赖这些系统如何在内存中表示数据,因为内存表示可能会因处理器体系结构、编译器选项和许多其他因素而异。您应该使用某个库进行序列化,因为该库的作者已经对您可能不感兴趣的各种问题投入了很多想法。

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.

五里雾 2024-12-15 01:22:41

您可以使用 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.

攒一口袋星星 2024-12-15 01:22:41

在一般情况下,您不应该对字节顺序、字段大小、结构打包等做出假设。对于一般应用程序或库开发,这样做是不好的做法。

也就是说,在嵌入式系统上工作时,我经常做这种事情,其中​​ 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.

浮生未歇 2024-12-15 01:22:41

您可以尝试 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.

不念旧人 2024-12-15 01:22:41

为什么不在调用 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 :)

娜些时光,永不杰束 2024-12-15 01:22:41

我不清楚问题是什么。 Windows 和 Linux 都将 bool 定义为一字节对象。

Windows确实BOOL定义为int,因此如果您将BOOL放在电线上并读取它作为一个 bool (或者将一个 bool 放在电线上并将其读取为 BOOL),那么你就会遇到麻烦。这相对容易修复。

Windows 和 Linux 可能为 falsetrue 定义了不同的值(更有可能的是,他们同意 false0 code>,但不同意 true 使用的值;即使在网络编程之外,也可能存在非 true< 的 bool 变量/code> 或false,见下文)。该标准要求 bool 至少为一个字节,并且一个字节具有远远超过两个可能的值。

是的,将您的 bool 转换为 unsigned char 并通过线路发送就可以正常工作。


注意:“bool 变量不是 truefalse”:

// obviously this code won't show up in anybody's code base
char a = 'a';
bool b = *reinterpret_cast<bool*>(&a);
switch (b) {
    case true:
       std::printf("true\n");
       break;
    case false:
       std::printf("false\n");
       break;
    default:
       std::printf("huh?\n");
       break;
 }

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 an int, so if you're putting a BOOL on the wire and reading it as a bool (or putting a bool on the wire and reading it as a BOOL) 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 and true (more likely, they agree that false is 0, but don't agree on the value used for true; even outside of network programming it's possible to have bool variables that are aren't true orfalse, see below). The Standard requires that bools be at least one byte, and a byte has far more than two possible values.

Yes, converting your bools to unsigned chars and sending that over the wire will work fine.


Note: "bool variables that are aren't true or false":

// obviously this code won't show up in anybody's code base
char a = 'a';
bool b = *reinterpret_cast<bool*>(&a);
switch (b) {
    case true:
       std::printf("true\n");
       break;
    case false:
       std::printf("false\n");
       break;
    default:
       std::printf("huh?\n");
       break;
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文