int8_t和uint8_t是char类型吗?

时间:2013-04-09 20:20:04

标签: c++ c++11 iostream language-lawyer standard-library

鉴于这个C ++ 11程序,我应该期待看到一个数字还是一个字母?还是没有期望?

#include <cstdint>
#include <iostream>

int main()
{
    int8_t i = 65;
    std::cout << i;
}

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

5 个答案:

答案 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”。在此列表中,每种类型至少提供与列表中前面的存储一样多的存储空间。可能还有实现定义的扩展有符号整数类型。标准和扩展有符号整数类型统称为有符号整数类型

     

...

     

类型boolcharchar16_tchar32_twchar_t以及有符号和无符号整数类型统称为整数类型< / em>的。整数类型的同义词是整数类型

§3.9.1还声明:

  

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

很有可能得出结论:int8_t可能是char提供的char个对象采用签名值的typedef;但是,情况并非如此,因为char不在有符号整数类型(标准和可能扩展的有符号整数类型)列表中。另请参阅std::make_unsignedstd::make_signed上的Stephan T. Lavavej's comments

因此,int8_tsigned 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_tunsigned 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位的预定义整数类型是charunsigned charsigned charshortunsigned 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_tuint8_t。在C中,它们是否是字符类型并不特别重要;没有任何操作可以区分真正的区别。 (偶数putc()是标准C中最低级别的字符输出例程,它将字符打印为int参数。 int8_tuint8_t,如果定义它们,几乎肯定会被定义为字符类型 - 但字符类型只是小整数类型。

C ++为operator<<charsigned char提供unsigned char的特定重载版本,以便std::cout << 'A'std::cout << 65产生非常不同的输出。后来,C ++采用了int8_tuint8_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_tsigned char或8位长扩展(非标准)有符号整数类型。

glibc(GNU C库)和Visual Studio C库都将int8_t定义为signed char。英特尔和Clang,至少在Linux上,也使用libc,因此同样适用于它们。因此,在最受欢迎的平台int8_tsigned 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 typedefbasic_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_tsigned 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段说:

  

类型boolcharchar16_tchar32_twchar_t以及有符号和无符号整数类型是统一的称为整数类型。整数类型的同义词是整数类型

因此,char是整数类型,但 char既不是有符号整数类型也不是无符号整数类型,第18.4.1节(上面引用)说{ {1}},如果存在,则为有符号整数类型的int8_t

可能令人困惑的是,根据实施情况,typedef可以采用与char相同的值。特别是,signed char可能有一个标志,但它仍然不是char。第3.9.1 / 1节明确说明了这一点:

  

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

这也意味着unsigned char 是3.9.1 / 2定义的有符号整数类型。

第3 即可。我承认我的解释,特别是句子&#34; char既不是有符号整数类型也不是无符号整数类型&#34;有点争议。

为了强化我的观点,我想补充一点,Stephan T. Lavavej说同样的事情hereJohannes Schaub - litbthis帖子的评论中也使用了相同的句子。

答案 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版本。