有一个地方在标准中用到了“std::size_t
的带符号版本”(以及std::ptrdiff_t
的无符号版本): printf
格式说明符%zu
适用于std::size_t
对象。%zd
适用于,正如C++标准所引用的C标准所说的,“与std::size_t
相应的有符号整数类型的对象”。
std::printf("%zu %zd %td %tu",
std::size_t{0}, std::make_signed_t<std::size_t>{0},
std::ptrdiff_t{0}, std::make_unsigned_t<std::ptrdiff_t>{0}
);
由于不存在特别命名的类型来表示 `%zd` 和 `%tu`,我倾向于相信没有所需的标准名称(除了 `std::make_signed_t`)。
另外,想要一个有符号变量版本的 `std::size_t` 没有太多理由:`std::size_t` 用于对象的大小,而对象的大小不是有符号的。
`ssize_t` 只保证保存 `-1` 或非负值。它保证的范围是 `[-1, SSIZE_MAX]`(这是 POSIX 特定类型,不是标准 C++ 类型)。这是因为它用于“无符号值或错误时为-1”。
C++ 标准库只使用 `std::size_t` 来表示这一点,而使用 `std::size_t(-1) == SIZE_MAX` 来表示错误/特殊值(参见:`std::basic_string<...>::npos`,`std::dynamic_extent`),因此,如果您需要错误值(或者可能是 `std::optional`),则可以直接使用 `std::size_t`,而不是 `ssize_t`。
如果您需要“表示大小但带符号性质的东西”,则 `std::ssize(c)` (“signed size”)返回 `std::common_type_t>`。对于数组类型,`std::ssize` 返回 `std::ptrdiff_t`。因此,这种情况下可能要使用 `std::ptrdiff_t`。
如果您需要“表示两个迭代器(包括指针)之间距离的类型”,则 `std::ptrdiff_t` 就是为此而生。这基本上与有符号大小的概念相一致,而 `std::iterator_traits<...>::difference_type` 通常是 `std::ptrdiff_t`。
这并不意味着 `sizeof(std::ptrdiff_t) == sizeof(std::size_t)`。标准没有定义它们之间的任何关系。 `sizeof(std::ptrdiff_t)sizeof(std::size_t)` 都似乎理论上是可能的,但我没有找到任何这样的系统。因此,在所有平台上都可以使用简单的断言并允许您只使用 `std::ptrdiff_t`:
static_assert(
sizeof(std::size_t) == sizeof(std::ptrdiff_t) &&
static_cast<std::size_t>(std::numeric_limits<std::ptrdiff_t>::max()) == std::numeric_limits<std::size_t>::max() / 2u,
"ptrdiff_t and size_t are not compatible"
);
有许多系统中,std::size_t
是 unsigned int
,而 std::ptrdiff_t
是 signed long
,但是 sizeof(int) == sizeof(long)
,所以我们必须检查类型的范围,而不是使用 std::is_same_v<std::ptrdiff_t, std::make_signed_t<std::size_t>>
进行判断。
或者,您可以直接使用 std::make_signed_t<std::size_t>
。
static_assert
:static_assert(sizeof(std::size_t) == sizeof(std::ptrdiff_t), "error message");
。这是我所知道的最好方法。 - NathanOliverptrdiff_t
可以用作有符号的size_t
,但你必须检查以确保吗? - Artyssize_t
不是标准的 C++ 类型,而是 POSIX 的类型。但是,如果你需要一个有符号的size_t
版本,那么你的方法似乎可行。我猜测没有标准的类型是因为负数的 "大小" 实际上并不存在,因此标准更喜欢使用类似ptrdiff_t
这样更有意义的名称来表示需要这样的东西。 - HTNWstd::ssize
,但它可能比size_t
更大。 - user975989ssize
,那么也会有相应的std::make_unsigned
。哦,在这个问题上,是否有人确切地知道“与 T 对应的有符号整数类型”根据std::make_signed
是否保证大小相同,或者是否还有其他逻辑?std::make_unsigned
的页面很具体,但仅涉及枚举。 - John P