标准 C++ 库中 size_t 的有符号变体

Art*_*oul 7 c++ unsigned signed std size-t

标准 C++ 中是否有 size_t 的有符号变体?意味着与 size_t 完全相同的位大小,但有符号。

我当然可以这样做:

#include <type_traits>
using signed_size_t = std::make_signed_t<std::size_t>;
Run Code Online (Sandbox Code Playgroud)

但也许标准库中已经有类似的定义,而不是发明额外的类型名称?

我知道有 ssize_t 和 ptrdiff_t,都有签名。但根据他们的描述,它们似乎都可以具有与 size_t 不同的位大小。但我需要与 size_t 完全相同的位大小,但已签名。

Art*_*yer 7

标准中有一处出现了“有符号版本std::size_t”(以及无符号版本):格式说明符用于对象。是针对对象的,正如 C++ 标准所指的 C 标准所说,“相应的有符号整数类型 [of ]”std::ptrdiff_tprintf%zustd::size_t%zdstd::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}
);
Run Code Online (Sandbox Code Playgroud)

由于没有专门为%zdand命名的类型%tu,我倾向于相信没有像您想要的标准名称(除了 as 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于此目的, withstd::size_t(-1) == SIZE_MAX相反 来指示错误/特殊值(请参阅:std::basic_string<...>::npos, std::dynamic_extent),因此如果您想要错误值(或者可能 ),您可以std::size_tssize_t使用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"
);
Run Code Online (Sandbox Code Playgroud)

(有很多系统std::size_tisunsigned intstd::ptrdiff_tis signed longbut 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>