使用按位或代替std :: max进行缓冲区大小调整

时间:2016-06-27 20:47:25

标签: c++ struct bit-manipulation sizeof bitwise-or

我正在查看一些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)编译器。

CON:

  • 它的大小几乎是必要的两倍。
  • 这使得人们更难以确定离线的确切缓冲区大小。
  • 奇怪/意外。

4 个答案:

答案 0 :(得分:3)

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

然而,这是非常令人困惑的,你必须停下来思考它。另外,如果你有两个8和7的尺码,你最终会得到15,这可能不是你想要的。值得庆幸的是,std::maxconstexpr重载需要initializer_list<T>,所以请使用:{/ p>

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

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

答案 1 :(得分:2)

写下意图:

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

在混淆事物方面没有“亲”。

答案 2 :(得分:2)

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

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

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

sizeof(Commands);

如果你将它与包含数据包标题的结构相结合,然后是union ...

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;
};

答案 3 :(得分:0)

看起来很漂亮。我使用sizeof(union { S1 s1; S2 s2; S3 s3; S4 s4; S5 s5; S6 s6; })。 (未经测试)