在标准中出现“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 的签名变体: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::size_t 而不是@ 987654342@ 如果你想要一个错误值(或者可能是std::optional<std::size_t>)
如果您想要“代表大小但已签名的东西”,std::ssize(c) ("signed size") 将返回 std::common_type_t<std::ptrdiff_t, std::make_signed_t<decltype(c.size())>>。对于数组类型,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) 和 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>。