编译时字节序相关表达式?

问题描述 投票:0回答:1

在实现 UDP BitTorrent 跟踪器协议时,我注意到最常见的数据包解析步骤是检查前 64 位是否是协议 id

0x41727101980
,用于请求连接,然后再假设它是给出的连接 id 之一。

我意识到,当连接 id 只是用作唯一的位序列时,它的字节顺序并不重要,因此我有一个想法,就是不将其从网络字节顺序转换为主机,而只是按原样使用这些值,但是只有一个问题,所写的协议 id 与以大端编码的数据包中的协议 id 不匹配,除非代码在大端机器上运行,所以我必须始终在某个地方转换前 64 位。

我知道我可以在运行时转换该值一次,但也许有一些 hack 允许在

0x41727101980
中表达这个值
uint64_t
,这确保无论系统的字节序如何,它总是以大字节序编码?

我真正想知道的是是否相当于:

static uint64_t const PROTOCOL_ID = htobe64(0x41727101980);

在编译时是可能的。

c constants endianness compile-time
1个回答
0
投票

BitTorrent 协议表示 “所有值均按网络字节顺序(大端)发送” 并针对连接请求显示此内容:

connect request:

Offset  Size            Name            Value
0       64-bit integer  protocol_id     0x41727101980 // magic constant

然后只需将最高有效字节放置在最小内存地址,直到将存储在最大内存地址的最低有效字节。

  • 将您感兴趣的值中的字节一直右移,使其占据位0-7。
  • 二进制 AND
    0xFF
    删除第 8 位及以上。
  • 向左移动到位
  • 对值中的所有字节执行此操作,并对所有结果进行二进制或以形成新值。

它可能看起来像这样:

#include <concepts>
#include <utility>

template <class T>
    requires(std::unsigned_integral<T>)
constexpr T htobe(T val) {
    return [val]<std::size_t... I>(std::index_sequence<I...>) {
        return (... | ((val >> ((8 * (sizeof(T) - I - 1))) & 0xFF) << (8 * I)));
    }(std::make_index_sequence<sizeof(T)>());
}

constexpr auto PROTOCOL_ID = htobe(0x41727101980u);

注意:这是假设您的系统上一个字节有 8 位。如果你想让它在其他系统上工作,你需要使用

CHAR_BIT
来调整位移位。

演示

© www.soinside.com 2019 - 2024. All rights reserved.