是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 。…
types
bool
,char
,char16_t
,char32_t
,wchar_t
以及有符号和无符号整数types统称为整型 。 整数types的同义词是整数types 。
§3.9.1还规定:
在任何特定的实现中,一个普通的
char
对象可以采用与signed char
或unsigned char
相同的值; 哪一个是实现定义的。
我们很容易得出这样的结论: int8_t
可能是char
的typedef, char
对象是带符号的值; 然而,情况并非如此,因为char
不在有符号整数types (标准和可能的扩展有符号整数types)列表中。 另请参阅Stephan T. Lavavej对std::make_unsigned
和std::make_signed
的评论 。
因此, int8_t
是一个有signed char
types定义,或者是一个扩展的有符号整数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
的typedeftemplate<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
将被提升为int
并basic_ostream<charT,traits>& operator<<(int n)
成员函数。
在std::cout << u
u
uint8_t
对象的情况下:
- 如果
uint8_t
是unsigned 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是char
, unsigned char
和signed char
。 short
和unsigned 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,当char
types可用时,没有特别的理由来定义8位扩展整数types。
更新 :
我对这个结论并不完全感到满意。 在C99中引入了int8_t
和uint8_t
。 在C中,它们是否是字符types并不重要, 没有什么操作可以区分真正的区别。 (即使putc()
是标准C中的最低级字符输出例程,也需要将该字符作为int
参数进行打印)。 int8_t
和uint8_t
,如果它们被定义,几乎肯定会被定义为字符types – 但是字符types只是小整数types。
C ++为char
, signed char
和unsigned char
提供了operator<<
特定的重载版本,所以std::cout << 'A'
和std::cout << 65
产生非常不同的输出。 后来,C ++采用了int8_t
和uint8_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*_t
types的好处胜过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
符号整数typesint8_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 char , short int , int , long int和long 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_t
是char
的typedef
的可能性添加了以下注释。
如上所述,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段说:
types
bool
,char
,char16_t
,char32_t
,wchar_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
char
,signed char
和unsigned char
是三种不同的types 。 […]在任何特定的实现中,一个普通的char
对象可以采用与signed char
或unsigned 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版本>>
。