鉴于这个C ++ 11程序,我应该期待看到一个数字还是一个字母?还是没有期望?
#include <cstdint>
#include <iostream>
int main()
{
int8_t i = 65;
std::cout << i;
}
标准是否指定此类型是否可以是字符类型?
答案 0 :(得分:25)
从C ++ 0x FDIS(N3290)的第18.4.1节[cstdint.syn]开始,int8_t
是一个可选的typedef,其指定如下:
namespace std {
typedef signed integer type int8_t; // optional
//...
} // namespace std
§3.9.1[basic.fundamental]陈述:
有五种标准有符号整数类型:“
signed char
”,“short int
”,“int
”,“long int
”,和“long long int
”。在此列表中,每种类型至少提供与列表中前面的存储一样多的存储空间。可能还有实现定义的扩展有符号整数类型。标准和扩展有符号整数类型统称为有符号整数类型。...
类型
bool
,char
,char16_t
,char32_t
,wchar_t
以及有符号和无符号整数类型统称为整数类型< / em>的。整数类型的同义词是整数类型。
§3.9.1还声明:
在任何特定实现中,普通
char
对象可以采用与signed char
或unsigned char
相同的值;哪一个是实现定义的。
很有可能得出结论:int8_t
可能是char
提供的char
个对象采用签名值的typedef;但是,情况并非如此,因为char
不在有符号整数类型(标准和可能扩展的有符号整数类型)列表中。另请参阅std::make_unsigned
和std::make_signed
上的Stephan T. Lavavej's comments。
因此,int8_t
是signed char
的typedef,或者是扩展的有符号整数类型,其对象恰好占用8位存储空间。
要回答你的问题,你不应该做出假设。由于已经定义了x.operator<<(y)
和operator<<(x,y)
两种形式的函数,§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从候选函数集中选择。然后我们查看§13.3.3.2[over.ics.rank]以确定:
template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char)
是int8_t
的完全匹配(即signed char
的typedef),则会调用signed char
模板。int8_t
将被提升为int
,并且会调用basic_ostream<charT,traits>& operator<<(int n)
成员函数。对于std::cout << u
u
uint8_t
个对象template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char)
:
uint8_t
是unsigned char
的完全匹配,则会调用int
模板。uint8_t
可以代表所有uint8_t
值,int
将被提升为basic_ostream<charT,traits>& operator<<(int n)
,并且会调用std::cout << static_cast<signed char>(i);
成员函数。< / LI>
如果您总是想要打印字符,最安全,最明确的选项是:
std::cout << static_cast<int>(i);
如果你总想打印一个数字:
{{1}}
答案 1 :(得分:23)
int8_t
正好是8位宽(如果存在)。
唯一可以是8位的预定义整数类型是char
,unsigned char
和signed char
。 short
和unsigned short
都必须至少为16位。
所以int8_t
必须是signed char
或普通char
的typedef(后者如果签署了普通char
)。
如果要将int8_t
值打印为整数而不是字符,可以将其显式转换为int
。
原则上,C ++编译器可以定义一个8位扩展整数类型(可能称为__int8
),并使int8_t
成为一个typedef。我能想到的唯一原因是避免使int8_t
成为一个字符类型。我不知道任何实际上已经完成此任务的C ++编译器。
C99中引入了int8_t
和扩展整数类型。对于C,当char
类型可用时,没有特别的理由来定义8位扩展整数类型。
<强>更新强>:
我对这个结论并不完全满意。 C99中介绍了int8_t
和uint8_t
。在C中,它们是否是字符类型并不特别重要;没有任何操作可以区分真正的区别。 (偶数putc()
是标准C中最低级别的字符输出例程,它将字符打印为int
参数。 int8_t
和uint8_t
,如果定义它们,几乎肯定会被定义为字符类型 - 但字符类型只是小整数类型。
C ++为operator<<
,char
和signed char
提供unsigned char
的特定重载版本,以便std::cout << 'A'
和std::cout << 65
产生非常不同的输出。后来,C ++采用了int8_t
和uint8_t
,但是就像在C中一样,它们几乎肯定是字符类型。对于大多数操作而言,这与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
我认为问题的根源在于语言中缺少某些东西:非常窄的整数类型,不是字符类型。
至于意图,我可以推测委员会成员要么没有考虑这个问题,要么认为不值得解决。有人可能会争辩(而且我愿意)将[u]int*_t
类型添加到标准中的好处超过了std::cout << ...
的奇怪行为带来的不便。
答案 2 :(得分:6)
我会以相反的顺序回答你的问题。
标准是否指定此类型是否可以是字符类型?
简短回答:int8_t
在最受欢迎的平台上是signed char
(Linux上的GCC / Intel / Clang和Windows上的Visual Studio),但在其他平台上可能是其他内容
接下来的答案很长。
C ++ 11标准的第18.4.1节提供了<cstdint>
的概要,其中包括以下内容
typedef
签名整数类型int8_t; //optional
稍后在同一部分第2段中,它说
标题[
<cstdint>
]定义所有函数,类型和宏,与 C标准中的7.18相同。
其中C标准表示C99为1.1 / 2:
C ++是一种基于C编程语言的通用编程语言,如 ISO / IEC 9899:1999编程语言 - C (以下简称 C标准< /强>)。
因此,int8_t
的定义可在C99标准的第7.18节中找到。更准确地说,C99的第7.18.1.1节说
typedef
名称intN_t
指定带宽为N
的有符号整数类型,无填充位和二进制补码表示。因此, int8_t表示有符号整数类型,宽度恰好为8位。
此外,C99的6.2.5 / 4节说
有五种标准有符号整数类型,指定为 signed char , short int , int ,< strong> long int 和 long long int 。 (这些和其他类型可以用其他几种方式指定,如6.7.2中所述。)也可能有实现定义的扩展有符号整数类型。 标准和扩展有符号整数类型统称为有符号整数类型。
最后,C99的5.2.4.2.1节规定了标准有符号整数类型的最小大小。排除signed char
,其他所有其他长度至少为16位。
因此,int8_t
是signed char
或8位长扩展(非标准)有符号整数类型。
glibc(GNU C库)和Visual Studio C库都将int8_t
定义为signed char
。英特尔和Clang,至少在Linux上,也使用libc,因此同样适用于它们。因此,在最受欢迎的平台int8_t
是signed char
。
鉴于这个C ++ 11程序,我应该期待看到一个数字还是一个字母?还是没有期望?
简短回答:在最受欢迎的平台(Linux上的GCC / Intel / Clang和Windows上的Visual Studio)中,您肯定会看到字母“A&#39;”。在其他平台中,您可能会看到65
。 (感谢DyP向我指出这一点。)
在续集中,所有引用都是针对C ++ 11标准(当前草案,N3485)。
第27.4.1节提供了<iostream>
的概要,特别是它陈述了cout
的声明:
extern ostream cout;
现在,根据第27.7.1节ostream
typedef
是basic_ostream
的模板专精化:
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
是扩展有符号整数类型的情况。显然,标准并没有为非标准类型指定operator<<()
的重载,但是由于促销和转换,所提供的重载之一可能会接受该调用。实际上,int
长度至少为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&lt;&lt;(int n);
将被调用。这意味着,这段代码
int8_t i = 65;
std::cout << i;
将打印65
。
<强>更新强>
<强> 1 即可。更正了DyP评论后的帖子。
<强> 2 即可。添加了以下评论int8_t
成为typedef
char
的可能性。
如上所述,C99标准(上面引用的第6.2.5 / 4节)定义了5个标准有符号整数类型(char
不是其中之一)并允许实现添加它们的onw,这些被称为非标准有符号整数类型。 C ++标准强化了第3.9.1 / 2节中的定义:
有五种标准的有符号整数类型:“signed char”,“short int”,“int”,“long int”和“long long int”[...]也可能有实现定义的扩展签名整数类型。标准和扩展有符号整数类型统称为有符号整数类型。
后来,在同一节中,第7段说:
类型
bool
,char
,char16_t
,char32_t
,wchar_t
,以及有符号和无符号整数类型是统一的称为整数类型。整数类型的同义词是整数类型。
因此,char
是整数类型,但 char
既不是有符号整数类型也不是无符号整数类型,第18.4.1节(上面引用)说{ {1}},如果存在,则为有符号整数类型的int8_t
。
可能令人困惑的是,根据实施情况,typedef
可以采用与char
相同的值。特别是,signed char
可能有一个标志,但它仍然不是char
。第3.9.1 / 1节明确说明了这一点:
[...]普通
signed char
,char
和signed char
三种不同类型。 [...]在任何特定实现中,普通unsigned char
对象可以采用与char
或signed char
相同的值;哪一个是实现定义的。
这也意味着unsigned char
不是3.9.1 / 2定义的有符号整数类型。
第3 即可。我承认我的解释,特别是句子&#34; char
既不是有符号整数类型也不是无符号整数类型&#34;有点争议。
为了强化我的观点,我想补充一点,Stephan T. Lavavej说同样的事情here和Johannes Schaub - litb在this帖子的评论中也使用了相同的句子。
答案 3 :(得分:5)
我的工作草案N3376在[cstdint.syn]§18.4.1中规定int类型通常是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位,因此可以接受将char定义为char。
答案 4 :(得分:-1)
char
/ signed char
/ unsigned char
是三种不同的类型,而char
并不总是8位。在大多数平台上,它们都是8位整数,但std :: ostream仅为>>
等行为定义了scanf("%c", ...)
的char版本。