Dre*_*ann 57 c++ iostream standard-library language-lawyer c++11
鉴于这个C++ 11程序,我应该期待看到一个数字还是一个字母?还是没有期望?
#include <cstdint>
#include <iostream>
int main()
{
int8_t i = 65;
std::cout << i;
}
Run Code Online (Sandbox Code Playgroud)
标准是否指定此类型是否可以是字符类型?
Dan*_*ien 25
从C++ 0x FDIS(N3290)的第18.4.1节[cstdint.syn]开始,int8_t
是一个可选的typedef,其指定如下:
namespace std {
typedef signed integer type int8_t; // optional
//...
} // namespace std
Run Code Online (Sandbox Code Playgroud)
§3.9.1[basic.fundamental]陈述:
有五种标准的有符号整数类型:"
signed char
","short int
","int
","long int
"和"long long int
".在此列表中,每种类型至少提供与列表中前面的存储一样多的存储空间.也可能存在实现定义的扩展有符号整数类型.标准和扩展有符号整数类型统称为有符号整数类型....
类型
bool
,char
,char16_t
,char32_t
,wchar_t
,和符号和无符号整数类型统称为整数类型.整数类型的同义词是整数类型.
§3.9.1还规定:
在任何特定实现中,普通
char
对象可以采用与asigned char
或a相同的值unsigned char
; 哪一个是实现定义的.
很有int8_t
可能得出结论,可能是char
提供的char
对象采用带符号值的typedef ; 但是,情况并非如此,因为char
不在有符号整数类型列表中(标准和可能扩展的有符号整数类型).另见Stephan T. Lavavej对std::make_unsigned
和的评论std::make_signed
.
因此,要么int8_t
是typedef ,要么是signed char
扩展的有符号整数类型,其对象恰好占用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);
Run Code Online (Sandbox Code Playgroud)
如果你总想打印一个数字:
std::cout << static_cast<int>(i);
Run Code Online (Sandbox Code Playgroud)
Kei*_*son 23
int8_t
正好是8位宽(如果存在的话).
唯一预定义整数类型,可以是8位是char
,unsigned char
,和signed char
.二者short
并unsigned short
需要是至少16位.
所以int8_t
必须是一个signed char
或者普通的typedef char
(后者如果plain char
是签名的话).
如果要将int8_t
值打印为整数而不是字符,则可以将其显式转换为int
.
原则上,C++编译器可以定义一个8位扩展整数类型(可能称为类似__int8
),并int8_t
为它创建一个typedef.我能想到这样做的唯一原因是避免制作int8_t
一个字符类型.我不知道任何实际上已经完成此任务的C++编译器.
int8_t
在C99中引入了两种和扩展的整数类型.对于C,当char
类型可用时,没有特别的理由来定义8位扩展整数类型.
更新:
我对这个结论并不完全满意.int8_t
并uint8_t
在C99中介绍.在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;
Run Code Online (Sandbox Code Playgroud)
可能会打印这封信A
而不是数字65
.
如果您想要一致的行为,请添加一个演员:
uint8_t x = 65;
std::cout << int(x); // or static_cast<int>(x) if you prefer
Run Code Online (Sandbox Code Playgroud)
我认为问题的根源在于语言中缺少某些东西:非常窄的整数类型,它们不是字符类型.
至于意图,我可以推测委员会成员要么没有考虑这个问题,要么认为不值得解决.有人可能会争辩(而且我会)认为[u]int*_t
将标准类型添加到标准中的好处超过了它们相当奇怪的行为带来的不便std::cout << ...
.
我会以相反的顺序回答你的问题.
标准是否指定此类型是否可以是字符类型?
简短的回答:int8_t
是signed char
最流行的平台(Linux上的GCC/Intel/Clang和Windows上的Visual Studio),但在其他平台上可能是其他东西.
答案如下.
C++ 11标准的第18.4.1节提供了<cstdint>
包含以下内容的概要
typedef
有符号整数类型int8_t; //optional
它说,在同一部分第2段后面
header [
<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,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'.在其他平台中,您可能会看到65
.(感谢DyP向我指出这一点.)
在续集中,所有引用都是针对C++ 11标准(当前草案,N3485).
第27.4.1节提供了概要<iostream>
,特别是它声明cout
:
extern ostream cout;
Run Code Online (Sandbox Code Playgroud)
现在,ostream
是按照第27.7.1节typedef
的模板basic_ostream
特化:
template <class charT, class traits = char_traits<charT> >
class basic_ostream;
typedef basic_ostream<char> ostream;
Run Code Online (Sandbox Code Playgroud)
第27.7.3.6.4节提供以下声明:
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c);
Run Code Online (Sandbox Code Playgroud)
如果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 <<(int n);
将被召唤.这意味着,这段代码
int8_t i = 65;
std::cout << i;
Run Code Online (Sandbox Code Playgroud)
将打印65
.
更新:
1.纠正了DyP评论后的帖子.
2.添加以下关于int8_t
成为typedef
for 的可能性的评论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节(上面引用)表示int8_t
,当存在时,是一个typedef
有符号整数类型.
可能令人困惑的是,取决于实现,char
可以采用与a相同的值signed char
.特别是,char
可能有一个标志,但它仍然不是signed char
.第3.9.1/1节明确说明了这一点:
[...]平原
char
,signed char
并且unsigned char
是三种不同的类型.[...]在任何特定实现中,普通char
对象可以采用与asigned char
或a相同的值unsigned char
; 哪一个是实现定义的.
这也意味着char
是不带符号的整数类型由3.9.1/2所定义的.
3.我承认我的解释,特别是句子" char
既不是有符号整数类型也不是无符号整数类型"有点争议.
为了加强我的实力,我想补充一点,Stephan T. Lavavej在这里说同样的事情,Johannes Schaub - litb在这篇文章的评论中也使用了相同的句子.
我有的工作草案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
Run Code Online (Sandbox Code Playgroud)
由于唯一的要求是它必须是8位,因此可以接受char的typedef.
归档时间: |
|
查看次数: |
20765 次 |
最近记录: |