4

我正在查看一些 C++ 网络代码。当我去找出缓冲区有多大时,我发现了这样的东西:

static const uint32_t MAX_COMMAND_BUFFER =
        sizeof(struct S1) | sizeof(struct S2) | sizeof(struct S3) |
        sizeof(struct S4) | sizeof(struct S5) | sizeof(struct S6);

我相信这里的基本思想是缓冲区可以包含这 6 个结构中的任何一个。这是在外部范围声明的,因此它可用于稍后的外部范围uint8_t数组大小。

现在通常在这里我希望看到使用 std::max() 函数或三元运算符来计算这 6 个结构中最大的确切大小的东西。我以前从未见过上述成语,不得不停下来说服自己它会起作用。

因此,由于我是这方面的新手,我一般想知道这是多么有效,以及这样做的好处和缺点是什么。

我能看到的是——

亲:

  • 它应该始终为您提供至少与最大结构大小一样大的大小。如果空间不是很宝贵,这就是您真正需要的。
  • 它似乎在编译时是可计算的。
  • 它甚至可以使用非常旧的 C++(甚至 C)编译器。

缺点:

  • 它可以使尺寸几乎是必要的两倍。
  • 这使得人们更难以离线准确地确定缓冲区的大小。
  • 它奇怪/出乎意料。
4

4 回答 4

3

从某种意义上说,它MAX_COMMAND_BUFFER始终至少与这些结构的所有大小的最大值一样大是有效的。很容易验证这一点 - 按位 -|将所有大小加在一起将为您提供一个值,该值具有与最大大小相同的所有位,可能还有其他一些位。

但是,这非常令人困惑,您必须停下来考虑一下。另外,如果你有 8 和 7 两种尺寸,你最终会得到 15,这可能不是你想要的。值得庆幸的是,std::max有一个constexpr需要 的重载initializer_list<T>,所以只需使用它:

static constexpr size_t MAX_COMMAND_BUFFER =
//               ^^^^^^
        std::max({sizeof(struct S1), sizeof(struct S2), ..., sizeof(struct S6)});

如果您的编译器不支持该重载,那么编写可变参数函数模板来完成同样的事情非常简单。

于 2016-06-27T20:56:04.713 回答
2

只要写下意图:

#include <algorithm>
struct S1 {};
struct S2 {};
struct S3 {};
int main() {
    static const unsigned maximum = std::max({sizeof(S1), sizeof(S2), sizeof(S3) /*, ... */});
}

混淆事物没有“专业人士”。

于 2016-06-27T20:55:55.197 回答
2

我同意你的观点,我认为他们这样做的方式很时髦,也不是最理想的。

我以前做这种事情的方式是对所有结构进行联合,然后使用联合的大小......

union Commands {
  S1 s1;
  S2 s2;
  ...
  S6 s6;
};

sizeof(Commands);

如果你把它和一个保存你的数据包头的结构结合起来,然后是联合......

struct Packet {
  Header header;
  Commands command;
};

您可以在缓冲区中设置一个指针,并轻松访问所有数据...

Packet *packet = (Packet)&buf[0];
switch(packet->header.command_type) {
  case COMMAND_DO_STUFF:
    printf("%d\n", packet->command.s1.stuff);
    break;
  case COMMAND_QUIT:
    ..
    break;
};
于 2016-06-27T21:12:12.057 回答
0

这看起来很牛逼。我会用sizeof(union { S1 s1; S2 s2; S3 s3; S4 s4; S5 s5; S6 s6; }). (未测试)

于 2016-06-27T20:57:11.483 回答