intmax_t 和 uintmax_t 是否保证大小相同?

NO_*_*AME 27 c++ language-lawyer c++17

我需要知道是否intmax_t始终“相同类型”,除非uintmax_t使用二进制补码而不是无符号值。

或者用正式的术语来说,下面的代码是否总是在符合标准的编译器中编译?

#include <cstdint>

// The important assertion:
static_assert(sizeof(std::uintmax_t) == sizeof(std::intmax_t));
// Less important assertions:
static_assert(UINTMAX_MAX == static_cast<std::uintmax_t>(INTMAX_MAX) * 2 + 1);
static_assert(-static_cast<std::intmax_t>(UINTMAX_MAX / 2) - 1 == INTMAX_MIN);
Run Code Online (Sandbox Code Playgroud)

我对 C++17 特别感兴趣。

我知道 C++20 是强制执行二进制补码的标准的第一个版本,但变量的大小对我来说比表示形式更重要。

duc*_*uck 29

是的,uintmax_t保证是 的未签名副本intmax_t

根据 C 标准 (N1570 7.20.1):

当定义 typedef 名称仅因首字母不存在或存在而不同时u,它们应表示相应的有符号和无符号类型,如 6.2.5 中所述;提供这些对应类型之一的实现也应提供另一个。

(对于 C 标准库头的描述,C++ 简称为 C。

6.2.5 p6:

对于每个有符号整数类型,都有一个对应的(但不同的)无符号整数类型(用关键字指定unsigned),它使用相同的存储量(包括符号信息)并具有相同的对齐要求。

C++ 在这方面与 C 类似 ( [basic.fundamental]/3 ):

对于每个标准有符号整数类型,都存在一个对应的(但不同的)标准无符号整数类型[...],它与对应的有符号整数类型占用相同的存储量并具有相同的对齐要求;也就是说,每个有符号整数类型与其对应的无符号整数类型具有相同的对象表示形式。同样,对于每个扩展有符号整数类型,都存在具有相同存储量和对齐要求的相应扩展无符号整数类型。

这意味着intmax_tuintmax_t始终具有相同的大小。

但是,不能保证其他两个断言成立(C++20/C23 之前)。

  • @mirabilos:谢谢,是的,就可以了。要求有符号和无符号类型具有相同的值位数,并将值范围定义为 2 的补码或无符号,确实可以完全消除该漏洞。除了“unsigned char”和可选的固定宽度类型(如“uint64_t”/“int64_t”)之外,仍然可以有填充位,但有符号/无符号之间没有区别。(所以 `signed char` 现在也不能有填充。) (2认同)

Chr*_*sMM 11

从评论/标题来看,您似乎是在问它们是否需要相同的尺寸;在这种情况下,简短的答案是肯定的......长答案......有点:)

\n

引用自[basic.fundamental]/3(C++17 草案 N4713)

\n
\n

对于每个标准有符号整数类型,都存在相应的(但不同)标准无符号整数类型: \xe2\x80\x9cunsigned char\xe2\x80\x9d、\xe2\x80\x9cunsigned Short int\xe2\x80\x9d 、 \xe2\x80\x9cunsigned int\xe2\x80\x9d、\xe2\x80\x9cunsigned long int\xe2\x80\x9d 和 \xe2\x80\x9cunsigned long long int\xe2\x80\x9d,每个与其对应的有符号整数类型占用相同的存储量并具有相同的对齐要求。

\n
\n

(强调我的)

\n

这保证了未签名版本占用与其签名版本相同的大小。

\n

话虽这么说,标准[cstdint.syn]仅规定:

\n
\n

使用 intmax_t =有符号整数类型

\n

使用 uintmax_t =无符号整数类型

\n
\n

美国[basic.fundamental]/2

\n
\n

标准和扩展有符号整数类型统称为有符号整数类型

\n
\n

[basic.fundamental]/3各州

\n
\n

标准和扩展无符号整数类型\n统称为无符号整数类型

\n
\n

因此,从技术上讲,编译器不必将它们实现为同一类型,因为这是一个实现细节;但实际上,它们是相同的。

\n
\n

正如 duck 所指出的,C 标准确实表明带前缀u和不带u前缀的类型之间必须存在对应的版本。C 标准是通过引用的[cstdint.syn]/2

\n