在没有 numeric_limits 的情况下,static_cast<T>(-1) 是生成全一位数据的正确方法吗?

Is static_cast<T>(-1) the right way to generate all-one-bits data without numeric_limits?

我在无法访问 C++ 标准库的环境中编写 C++ 代码,特别是无法访问 std::numeric_limits。假设我要实现

template <typename T> constexpr T all_ones( /* ... */ )

专注于无符号整数类型,我在那里放什么?具体来说,static_cast<T>(-1) 够好吗? (其他类型我可以根据我猜的大小将其视为无符号字符数组。)

0 上使用 bitwise NOT 运算符 ~

T allOnes = ~(T)0;

A static_cast<T>(-1) 采用不可移植的二进制补码。如果您只关心无符号类型, 是正确的选择。

工作示例:https://ideone.com/iV28u0

Focusing on unsigned integral types, what do I put there? Specifically, is static_cast(-1) good enough

如果您只关心无符号类型,是的,转换 -1 对于所有标准 C++ 实现都是正确的。对无符号类型的操作,包括有符号类型到无符号类型的转换,保证以模数 (max+1) 工作。

这种非常直接的方式。

T allOnes;
memset(&allOnes, ~0, sizeof(T));

Focusing on unsigned integral types, what do I put there? Specifically, is static_cast(-1) good enough

是的,已经足够好了。

但我更喜欢十六进制值,因为我的背景是嵌入式系统,而且我一直都必须知道 sizeof(T)。

即使在桌面系统中,我们也知道以下 T 的大小:

uint8_t  allones8  = 0xff;
uint16_t allones16 = 0xffff;
uint32_t allones32 = 0xffffffff;
uint64_t allones64 = 0xffffffffffffffff;

另一种方式是

static_cast<T>(-1ull)

这会更正确并且适用于任何有符号整数格式,无论 1 的补码、2 的补码或符号大小如何。您也可以使用 static_cast<T>(-UINTMAX_C(1))

因为unary minus of an unsigned value定义为

The negative of an unsigned quantity is computed by subtracting its value from 2^n, where n is the number of bits in the promoted operand."

因此-1u总是return在unsigned int中的全1位数据。 ll 后缀是为了使其适用于任何比 unsigned long long 窄的类型。 C++ 中没有 extended integer types(还),所以这应该没问题

然而,表达意图更清晰的解决方案是

static_cast<T>(~0ull)