【问题标题】:Signed variant of size_t in standard C++ library标准 C++ 库中 size_t 的有符号变体
【发布时间】:2021-04-06 07:32:50
【问题描述】:

标准 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 完全相同但已签名的位大小。

【问题讨论】:

  • 但我需要与 size_t 完全相同但已签名的位大小。 为此,请使用 static_assertstatic_assert(sizeof(std::size_t) == sizeof(std::ptrdiff_t), "error message");。这是我所知道的最好的。
  • @NathanOliver 所以通常ptrdiff_t 可以用作签名size_t,但您必须检查才能确定?
  • std::streamsize "用作std::size_t的签名对应物,类似于POSIX类型ssize_t"。
  • 根据我的经验,这两种类型的大小相同。不能保证,但是使用静态断言,您基本上可以保证。
  • ssize_t 不是标准 C++;这是POSIX。但实际上,如果您需要size_t 的签名版本,那么您的方式似乎很好。我想没有一个标准的,因为负“大小”实际上并不存在,所以当它需要这样的东西时,标准更喜欢更有意义的名字,比如ptrdiff_t

标签: c++ unsigned signed c++-standard-library size-t


【解决方案1】:

在标准中出现“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&lt;std::size_t&gt; 除外)。


顺便说一句,没有太多理由需要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&lt;...&gt;::nposstd::dynamic_extent),因此您可以只使用std::size_t 而不是@ 987654342@ 如果你想要一个错误值(或者可能是std::optional&lt;std::size_t&gt;


如果您想要“代表大小但已签名的东西”,std::ssize(c) ("signed size") 将返回 std::common_type_t&lt;std::ptrdiff_t, std::make_signed_t&lt;decltype(c.size())&gt;&gt;。对于数组类型,std::ssize 返回std::ptrdiff_t。所以可能为此目的使用std::ptrdiff_t


如果你想要“用于表示两个迭代器之间距离的类型”(包括指针),std::ptrdiff_t 就是为此而生的。这大多与有符号大小的概念不谋而合,std::iterator_traits&lt;...&gt;::difference_type 通常是std::ptrdiff_t


这些并不意味着sizeof(std::ptrdiff_t) == sizeof(std::size_t)。该标准没有定义它们之间的任何关系。 sizeof(std::ptrdiff_t) &lt; sizeof(std::size_t)sizeof(std::ptrdiff_t) &gt; 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_tunsigned intstd::ptrdiff_tsigned longsizeof(int) == sizeof(long),所以我们必须检查类型的范围而不是std::is_same_v&lt;std::ptrdiff_t, std::make_signed_t&lt;std::size_t&gt;&gt;

或者像你已经拥有的那样使用std::make_signed_t&lt;std::size_t&gt;

【讨论】:

    猜你喜欢
    • 2015-04-29
    • 2020-01-05
    • 1970-01-01
    • 2018-11-24
    • 2010-12-26
    • 1970-01-01
    • 2017-04-22
    • 2020-07-21
    • 1970-01-01
    相关资源
    最近更新 更多