int8_t和uint8_t是char类型吗?

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对象可以采用与a signed char或a相同的值unsigned char; 哪一个是实现定义的.

很有int8_t可能得出结论,可能是char提供的char对象采用带符号值的typedef ; 但是,情况并非如此,因为char不在有符号整数类型列表中(标准和可能扩展的有符号整数类型).另见Stephan T. Lavavejstd::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 << uu一个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)

  • 虽然你的推理对我有意义,但我仍然相信我所说的.显然Stephan T. Lavavej [同意我](http://connect.microsoft.com/VisualStudio/feedback/details/764409/visual-studio-2012-c-std-make-unsigned):"虽然"char"是要求具有与"signed char"或"unsigned char"相同的签名和范围(其中一个是实现定义的),"char"既不是有符号整数类型也不是无符号整数类型".另见[Johannes Schaub - litb](http://stackoverflow.com/users/34509/johannes-schaub-litb)的评论[这里](http://stackoverflow.com/q/9285657/1137388) (3认同)

Kei*_*son 23

int8_t 正好是8位宽(如果存在的话).

唯一预定义整数类型,可以是8位是char,unsigned char,和signed char.二者shortunsigned 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_tuint8_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_tuint8_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 << ....

  • @MichaelBurr:如果`char`是16位,那么`CHAR_BIT == 16`,一个字节定义为16位.除了位字段,您不能有小于1个字节的整数类型.所以在那种情况下就没有`int8_t`.(如果你不相信,请考虑`sizeof(int8_t)`.) (8认同)
  • C++标准3.9.1:"有符号和无符号整数类型应满足C标准第5.2.4.2.1节中给出的约束".C 5.2.4.2.1设置`<limits.h>`的要求,包括`SHRT_MIN <= -32767`,`SHRT_MAX> = + 32767`和`USHRT_MAX> = 65535` (5认同)
  • 我试图找到一个最小尺寸为"short"的参考(除了至少"signed char"的大小),我找不到它 - 你能提供参考吗? (3认同)
  • 请记住,实现可以将`typedef``int8_t`转换为非标准实现定义类型(并且很可能在那些使用16位`char`的平台上).我认为C++ 11标准缺少关于这些`stdint.h`类型如何在重载中解决的必要说明.我怀疑这些类型如何匹配重载解析将是实现定义. (3认同)
  • @BenVoigt [over.ics.rank]/4:"标准转换序列按其排名排序:完全匹配是一种比促销更好的转换,这是一种比转换更好的转换." 在这种情况下,促销将是[conv.prom]/1,即促销到`(unsigned)int`(来自转换等级较低的类型).转换将是[conv.integral]/1,即转换为任何整数类型(包括`char`).只有`char == uint8_t`,最可行的函数应该是`operator <<(char)`AFAIK,否则`operator <<(int)`. (2认同)
  • 请注意,函数样式转换和`static_cast`在最后一个示例中不相同(函数样式转换可能合法地抛弃constness或重新解释) (2认同)

Cas*_*eri 6

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

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

简短的回答:int8_tsigned 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 intlong 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_tsigned char.英特尔和Clang,至少在Linux上,也使用libc,因此同样适用于它们.因此,在最流行的平台int8_tsigned 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成为typedeffor 的可能性的评论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对象可以采用与a signed char或a相同的值unsigned char; 哪一个是实现定义的.

这也意味着char带符号的整数类型由3.9.1/2所定义的.

3.我承认我的解释,特别是句子" char既不是有符号整数类型也不是无符号整数类型"有点争议.

为了加强我的实力,我想补充一点,Stephan T. Lavavej在这里说同样的事情,Johannes Schaub - litb这篇文章的评论中也使用了相同的句子.

  • 我不认为如果`int8_t!= signed char`将无法编译,原因如下:1)`int8_t`可能是`char`(与`signed char`不同的不同类型).2)即使`int8_t`是扩展整数类型,它也是整数类型,参见[basic.fundamental]/2 + 7.正如[conv.prom]/1告诉我们的那样,它可以被提升为`int`或`unsigned int`(因为`int`必须是> =`char`> = 8位).另见丹尼尔的回答. (2认同)

Rap*_*ptz 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
Run Code Online (Sandbox Code Playgroud)

由于唯一的要求是它必须是8位,因此可以接受char的typedef.