[英]Are intmax_t and uintmax_t guaranteed to be of the same size?
我需要知道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);
我對 C++17 特別感興趣。
我知道 C++20 是第一個強制執行二進制補碼的標准版本,但變量的大小對我來說比表示形式更重要。
是的, uintmax_t
保證是intmax_t
的無符號副本。
來自 C 標准(N1570 7.20.1):
當定義的 typedef 名稱僅在缺少或存在初始
u
時不同,它們應表示相應的有符號和無符號類型,如 6.2.5 中所述; 提供這些相應類型之一的實現也應提供另一個。
(C++對C標准庫頭文件的描述,簡單參考C。)
6.2.5 第 6 頁:
對於每個帶符號的 integer 類型,都有一個對應的(但不同的)無符號 integer 類型(用關鍵字
unsigned
指定),它使用相同的存儲量(包括符號信息)並且具有相同的 alignment 要求。
C++ 在這方面類似於 C ( [basic.fundamental]/3 ):
對於每個標准簽名 integer 類型,存在一個對應的(但不同的)標准無符號 integer 類型 [...] 也就是說,每個帶符號的 integer 類型與其對應的無符號 integer 類型具有相同的 object 表示。 同樣,對於每個擴展的有符號 integer 類型,都存在一個相應的擴展無符號 integer 類型,具有相同的存儲量和 alignment 要求。
這意味着intmax_t
和uintmax_t
總是具有相同的大小。
但是,不能保證其他兩個斷言會成立(在 C++20/C23 之前)。
從評論/標題來看,您似乎在問是否需要相同的尺寸; 在這種情況下,簡短的回答是肯定的......長答案......有點:)
引自[basic.fundamental]/3
(C++17 草案 N4713)
對於每個標准的有符號 integer 類型,存在一個對應的(但不同的)標准無符號 integer 類型:“unsigned char”、“unsigned short int”、“unsigned int”、“unsigned long int”和“unsigned long long int” ”,每個都占用相同的存儲量,並且與其對應的簽名 integer 類型具有相同的 alignment 要求。
(強調我的)
這保證了未簽名的版本占用與其簽名的等效版本相同的大小。
話雖這么說,標准[cstdint.syn]
只說明:
使用 intmax_t = signed integer 類型;
使用 uintmax_t = unsigned integer 類型;
[basic.fundamental]/2
狀態
標准和擴展簽名 integer 類型統稱為簽名 integer 類型。
和[basic.fundamental]/3
狀態
標准和擴展的unsigned integer類型統稱為unsigned integer類型
因此,從技術上講,編譯器不必將它們實現為相同的類型,因為那是一個實現細節; 但實際上,它們是一樣的。
正如鴨子所指出的,C 標准確實表明在帶有u
和沒有u
前綴的類型之間必須有對應的版本。 C 標准通過[cstdint.syn]/2
引用
我的回答被鴨子證明是不正確的。 謝謝鴨!
https://stackoverflow.com/a/75203111/2027196
我的原始答案以備將來參考:
標准不保證
uintmax_t
和intmax_t
具有相同的寬度,但是不存在具有現代 C 編譯器的系統,它們將具有不同的寬度。 甚至可能沒有非現代的 C 編譯器,它們將具有不同的寬度(在沒有證據的情況下斷言與“天空是藍色的”類型 arguments 相同)。
你能得到的最好的是
uintmax_t
和intmax_t
按照約定保證寬度相同。 我說“你能得到的最好的”,但我更願意依賴這種保證,而不是依賴編譯器完美地實現其所有邊緣情況 SFINAE 要求或類似要求。
將
static_assert
放在庫的頂部(可能在assumptions.hpp
文件中),然后再也不用擔心這個問題了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.