是int8_t和uint8_t打算是字符types?

鉴于这个C + + 11程序,我应该期望看到一个数字或字母? 还是不做预期?

#include <cstdint> #include <iostream> int main() { int8_t i = 65; std::cout << i; } 

标准是否指定此types是否可以是字符types?

从C ++ 0x FDIS(N3290)的int8_t [cstdint.syn]中, int8_t是一个可选的typedef,指定如下:

 namespace std { typedef signed integer type int8_t; // optional //... } // namespace std 

§3.9.1 [basic.fundamental]指出:

有五个标准的有符号整数types :“ signed char ”,“ short int ”,“ int ”,“ long int ”和“ long long int ”。 在这个列表中,每个types至less提供了与列表中的前一个相同的存储空间。 也可能有实现定义的扩展有符号整数types 。 标准和扩展的有符号整数types统称为有符号整数types

typesboolcharchar16_tchar32_twchar_t以及有符号和无符号整数types统称为整型整数types的同义词是整数types

§3.9.1还规定:

在任何特定的实现中,一个普通的char对象可以采用与signed charunsigned char相同的值; 哪一个是实现定义的。

我们很容易得出这样的结论: int8_t可能是char的typedef, char对象是带符号的值; 然而,情况并非如此,因为char不在有符号整数types (标准和可能的扩展有符号整数types)列表中。 另请参阅Stephan T. Lavavej对std::make_unsignedstd::make_signed 的评论 。

因此, int8_t是一个有signed chartypes定义,或者是一个扩展的有符号整数types,其对象占用8位的存储空间。

但是,要回答你的问题,你不应该做出假设。 因为已经定义了x.operator<<(y)operator<<(x,y)这两种forms的函数,所以第13.5.3节[over.binary]说我们引用第13.3.1.2节[over.match.oper ]来确定std::cout << i的解释。 §13.3.1.2依次说实现根据§13.3.2和§13.3.3从候选函数集中进行select。 然后我们看看§13.3.3.2[over.ics.rank]来确定:

  • 如果int8_t是有signed char的完全匹配(即,有signed char的typedef template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char)则将调用template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char)模板。
  • 否则, int8_t将被提升为intbasic_ostream<charT,traits>& operator<<(int n)成员函数。

std::cout << u u uint8_t对象的情况下:

  • 如果uint8_tunsigned char的完全匹配, unsigned char调用template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char)模板。
  • 否则,由于int可以表示所有的uint8_t值,所以uint8_t将被提升为int并且将basic_ostream<charT,traits>& operator<<(int n)成员函数。

如果你总是想打印一个字符,最安全和最明确的select是:

 std::cout << static_cast<signed char>(i); 

如果你总是想打印一个数字:

 std::cout << static_cast<int>(i); 

int8_t正好是8位宽(如果存在)。

唯一可以是8位的预定义整数types是charunsigned charsigned charshortunsigned short都要求至less有16位。

所以int8_t必须是有signed char或普通char (后者如果普通char被签名)的typedef。

如果你想打印一个int8_t值作为一个整数而不是一个字符,你可以明确地将其转换为int

原则上,C ++编译器可以定义一个8位扩展整数types (可能称为__int8 ),并使int8_t成为typedef。 我能想到这样做的唯一理由是避免使int8_t成为一种字符types。 我不知道有任何C ++编译器实际上已经这样做。

int8_t和扩展整数types都是在C99中引入的。 对于C,当chartypes可用时,没有特别的理由来定义8位扩展整数types。

更新

我对这个结论并不完全感到满意。 在C99中引入了int8_tuint8_t 。 在C中,它们是否是字符types并不重要, 没有什么操作可以区分真正的区别。 (即使putc()是标准C中的最低级字符输出例程,也需要将该字符作为int参数进行打印)。 int8_tuint8_t ,如果它们被定义,几乎肯定会被定义为字符types – 但是字符types只是小整数types。

C ++为charsigned charunsigned char提供了operator<<特定的重载版本,所以std::cout << 'A'std::cout << 65产生非常不同的输出。 后来,C ++采用了int8_tuint8_t ,但是和C一样,它们几乎可以肯定是字符types。 对于大多数操作来说,这并不比在C中更重要,但是对于std::cout << ...它确实有所作为,因为这是:

 uint8_t x = 65; std::cout << x; 

可能会打印字母A而不是数字65

如果你想要一致的行为,添加一个强制转换:

 uint8_t x = 65; std::cout << int(x); // or static_cast<int>(x) if you prefer 

我认为问题的根源在于语言中缺less一些东西:非常窄的整型不是字符types。

至于意图 ,我可以推测,委员会成员要么没有考虑这个问题,要么决定不值得处理。 有人可能会争论(我会)在标准中添加[u]int*_ttypes的好处胜过std::cout << ...的相当奇怪行为带来的不便。

我的工作草案副本N3376在[cstdint.syn]§18.4.1中指定inttypes通常是typedef。

 namespace std { typedef signed integer type int8_t; // optional typedef signed integer type int16_t; // optional typedef signed integer type int32_t; // optional typedef signed integer type int64_t; // optional typedef signed integer type int_fast8_t; typedef signed integer type int_fast16_t; typedef signed integer type int_fast32_t; typedef signed integer type int_fast64_t; typedef signed integer type int_least8_t; typedef signed integer type int_least16_t; typedef signed integer type int_least32_t; typedef signed integer type int_least64_t; typedef signed integer type intmax_t; typedef signed integer type intptr_t; // optional typedef unsigned integer type uint8_t; // optional typedef unsigned integer type uint16_t; // optional typedef unsigned integer type uint32_t; // optional typedef unsigned integer type uint64_t; // optional typedef unsigned integer type uint_fast8_t; typedef unsigned integer type uint_fast16_t; typedef unsigned integer type uint_fast32_t; typedef unsigned integer type uint_fast64_t; typedef unsigned integer type uint_least8_t; typedef unsigned integer type uint_least16_t; typedef unsigned integer type uint_least32_t; typedef unsigned integer type uint_least64_t; typedef unsigned integer type uintmax_t; typedef unsigned integer type uintptr_t; // optional } // namespace std 

由于唯一的要求是它必须是8位,所以typedef为char是可以接受的。

我会以相反的顺序回答你的问题。

标准是否指定此types是否可以是字符types?

简短的回答int8_t是在最stream行的平台(Linux上的GCC / Intel / Clang和Windows上的Visual Studio)中的有signed char ,但也可能是别的。

长的答案如下。

C ++ 11标准的第18.4.1节提供了<cstdint>的概要,其中包括以下内容

typedef 符号整数types int8_t; //optional int8_t; //optional

稍后在同一部分第2段中说

标题[ <cstdint> ]定义了与C标准中 7.18相同的所有函数,types和macros。

其中C标准是指1.1 / 2的C99:

C ++是一种基于ISO / IEC 9899:1999编程语言-C (以下简称C标准 )中描述的C编程语言的通用编程语言。

因此, int8_t的定义可以在C99标准的7.18节中find。 更确切地说,C99的7.18.1.1节说

typedef名称intN_t指定宽度为N ,无填充位和二进制补码表示的有符号整数types。 因此, int8_t表示宽度恰好为8位的有符号整数types

另外,C99的6.2.5 / 4节说

有五个标准的有符号整数types ,被指定为signed charshort intintlong intlong long int 。 (这些和其他types可以用其他几种方式来指定,如6.7.2所述)也可能有实现定义的扩展有符号整数types标准和扩展的有符号整数types统称为有符号整数types

最后,C99的第5.2.4.2.1节规定了标准的有符号整数types的最小尺寸。 不包括有signed char ,所有其他signed char至less有16位。

因此, int8_t是有signed char或一个8位长的扩展(非标准)有符号整数types。

glibc(GNU C库)和Visual Studio C库都将int8_t定义为signed char 。 Intel和Clang至less在Linux上也使用libc,因此,这同样适用于它们。 因此,在最stream行的平台int8_t是有signed char

鉴于这个C + + 11程序,我应该期望看到一个数字或字母? 还是不做预期?

简单的回答 :在最stream行的平台(Linux上的GCC / Intel / Clang和Windows上的Visual Studio)中,您肯定会看到字母“A”。 在其他平台上,你可能会看到65 。 (感谢DyP指出了这一点。)

在续集中,所有引用都是针对C ++ 11标准(当前的草案,N3485)。

第27.4.1节提供了<iostream>的概要,特别指出了cout的声明:

 extern ostream cout; 

现在, ostream是根据第27.7.1节的basic_ostream模板特化的typedef

 template <class charT, class traits = char_traits<charT> > class basic_ostream; typedef basic_ostream<char> ostream; 

第27.7.3.6.4节提供了下列声明:

 template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c); 

如果int8_t是有signed char那么就是这个被调用的重载。 同一节也指定这个调用的效果是打印字符(不是数字)。

现在,我们来考虑int8_t是一个扩展的有符号整数types的情况。 显然,标准没有为非标准types指定operator<<()重载,但是由于促销和转换,所提供的重载之一可能会接受调用。 实际上, int至less是16位,可以表示int8_t所有值。 然后4.5 / 1给int8_t可以提升int 。 另一方面,4.7 / 1和4.7 / 2给int8_t可以转换为有signed char 。 最后,13.3.3.1.1认为在超负荷解决过程中促销优于转换。 因此,下面的超载(在23.7.3.1中声明)

basic_ostream&basic_ostream :: operator <<(int n);

将被调用。 这意味着,这个代码

 int8_t i = 65; std::cout << i; 

将打印65

更新:

1 。 更正了DyP评论后的post。

2 。 对int8_tchartypedef的可能性添加了以下注释。

如上所述,C99标准(上面引用的6.2.5 / 4节)定义了5个标准的有符号整数types( char不是其中之一),并允许实现添加它们的onw,这些onw被称为非标准的有符号整数types。 C ++标准强化了3.9.1 / 2节的定义:

有五个标准的有符号整数types:“signed char”,“short int”,“int”,“long int”和“long long int”[…]也可能有实现定义的扩展有符号整数types。 标准和扩展的有符号整数types统称为有符号整数types

后来在同一节中,第7段说:

typesboolcharchar16_tchar32_twchar_t 以及有符号和无符号整数types统称为整型整数types的同义词是整数types

因此, char是一个整数types,但是char既不是一个有符号整数types,也不是一个无符号整数types,而Section 18.4.1(上面引用的)则表示int8_t存在时是一个有符号整数types的typedef

可能会令人困惑的是,根据实现, char可以采用与signed char相同的值。 特别是, char可能有一个符号,但它仍然不是一个有signed char 。 第3.9.1 / 1节明确提到:

Plain charsigned charunsigned char三种不同的types 。 […]在任何特定的实现中,一个普通的char对象可以采用与signed charunsigned char相同的值; 哪一个是实现定义的。

这也意味着char 不是 3.9.1 / 2定义的有符号整数types。

3 。 我承认我的解释,特别是句子“ char既不是有符号整数types也不是无符号整数types”是有点争议的。

为了强化我的观点,我想补充一点,Stephan T. Lavavej在这里说了同样的话, Johannes Schaub – litb也在这篇文章的评论中使用了同样的句子。

char / signed char / unsigned char是三种不同的types, char不总是8位。 在大多数平台上,他们都是8位整数,但是std :: ostream只有为scanf("%c", ...)等行为定义了char版本>>