标准 C++ 库中 size_t 的签名变体
Signed variant of size_t in standard C++ library
标准 C++ 中是否有 size_t 的签名变体?表示与 size_t 完全相同的位大小,但有符号。
我当然可以:
#include <type_traits>
using signed_size_t = std::make_signed_t<std::size_t>;
但也许标准库中已经有类似的定义,而不是发明额外的类型名称?
我知道有 ssize_t 和 ptrdiff_t,都签名了。但是根据他们的描述,它们的位大小似乎都与 size_t 不同。但我需要与 size_t 完全相同的位大小但已签名。
“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
代替表示 error/special 值(参见:std::basic_string<...>::npos
、std::dynamic_extent
) ,所以如果你想要一个错误值(或者可能是 std::optional<std::size_t>
)
,你可以只使用 std::size_t
而不是 ssize_t
如果您想要“表示尺寸但已签名的东西”,std::ssize(c)
(“已签名 size
”)returns std::common_type_t<std::ptrdiff_t, std::make_signed_t<decltype(c.size())>>
。对于数组类型,std::ssize
returns 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>
。
标准 C++ 中是否有 size_t 的签名变体?表示与 size_t 完全相同的位大小,但有符号。
我当然可以:
#include <type_traits>
using signed_size_t = std::make_signed_t<std::size_t>;
但也许标准库中已经有类似的定义,而不是发明额外的类型名称?
我知道有 ssize_t 和 ptrdiff_t,都签名了。但是根据他们的描述,它们的位大小似乎都与 size_t 不同。但我需要与 size_t 完全相同的位大小但已签名。
“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
代替表示 error/special 值(参见:std::basic_string<...>::npos
、std::dynamic_extent
) ,所以如果你想要一个错误值(或者可能是 std::optional<std::size_t>
)
std::size_t
而不是 ssize_t
如果您想要“表示尺寸但已签名的东西”,std::ssize(c)
(“已签名 size
”)returns std::common_type_t<std::ptrdiff_t, std::make_signed_t<decltype(c.size())>>
。对于数组类型,std::ssize
returns 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>
。