C++ int8_t 和 uint8_t 是 char 类型吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15911714/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:53:26  来源:igfitidea点击:

Are int8_t and uint8_t intended to be char types?

c++c++11iostreamlanguage-lawyerstandard-library

提问by Drew Dormann

Given this C++11 program, should I expect to see a number or a letter? Or not make expectations?

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

#include <cstdint>
#include <iostream>

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

Does the standard specify whether this type can or will be a character type?

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

采纳答案by Daniel Trebbien

From § 18.4.1 [cstdint.syn] of the C++0x FDIS (N3290), int8_tis an optional typedef that is specified as follows:

来自 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] states:

§ 3.9.1 [basic.fundamental] 指出:

There are five standard signed integer types: “signed char”, “short int”, “int”, “long int”, and “long long int”. In this list, each type provides at least as much storage as those preceding it in the list. There may also be implementation-defined extended signed integer types. The standard and extended signed integer types are collectively called signed integer types.

...

Types bool, char, char16_t, char32_t, wchar_t, and the signed and unsigned integer types are collectively called integral types. A synonym for integral type is integer type.

有五种标准的有符号整数类型:“ signed char”、“ short int”、“ int”、“ long int”和“ long long int”。在此列表中,每种类型至少提供与列表中它之前的类型一样多的存储空间。也可能有实现定义的扩展有符号整数类型。标准的和扩展的有符号整数类型统称为有符号整数类型

...

类型bool, char, char16_t, char32_t,wchar_t以及有符号和无符号整数类型统称为整型整数类型的同义词是整数类型

§ 3.9.1 also states:

§ 3.9.1 还指出:

In any particular implementation, a plain charobject can take on either the same values as a signed charor an unsigned char; which one is implementation-defined.

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

It is tempting to conclude that int8_tmay be a typedef of charprovided charobjects take on signed values; however, this is not the case as charis not among the list of signed integer types(standard and possibly extended signed integer types). See also Stephan T. Lavavej's commentson std::make_unsignedand std::make_signed.

很容易得出结论,int8_tchar提供char对象的 typedef 可能采用有符号值;然而,情况并非如此,因为char它不在有符号整数类型列表(标准和可能扩展的有符号整数类型)中。另请参阅Stephan T. Lavavejstd::make_unsigned的评论std::make_signed

Therefore, either int8_tis a typedef of signed charor it is an extended signed integer type whose objects occupy exactly 8 bits of storage.

因此,要么int8_t是 typedef要么是signed char扩展的有符号整数类型,其对象正好占用 8 位存储空间。

To answer your question, though, you should not make assumptions. Because functions of both forms x.operator<<(y)and operator<<(x,y)have been defined, § 13.5.3 [over.binary] says that we refer to § 13.3.1.2 [over.match.oper] to determine the interpretation of std::cout << i. § 13.3.1.2 in turn says that the implementation selects from the set of candidate functions according to § 13.3.2 and § 13.3.3. We then look to § 13.3.3.2 [over.ics.rank] to determine that:

但是,要回答您的问题,您不应该做出假设。因为两种形式的函数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] 来确定:

  • The template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char)template would be called if int8_tis an Exact Match for signed char(i.e. a typedef of signed char).
  • Otherwise, the int8_twould be promoted to intand the basic_ostream<charT,traits>& operator<<(int n)member function would be called.
  • template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char)模板会,如果被称为int8_t是一个精确匹配signed char(即的一个typedef signed char)。
  • 否则,int8_t将提升为intbasic_ostream<charT,traits>& operator<<(int n)调用成员函数。

In the case of std::cout << ufor ua uint8_tobject:

在的情况下std::cout << uu一个uint8_t对象:

  • The template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char)template would be called if uint8_tis an Exact Match for unsigned char.
  • Otherwise, since intcan represent all uint8_tvalues, the uint8_twould be promoted to intand the basic_ostream<charT,traits>& operator<<(int n)member function would be called.
  • template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char)如果模板将被称为uint8_t是一个精确匹配unsigned char
  • 否则,由于int可以表示所有uint8_t值,uint8_t将被提升为intbasic_ostream<charT,traits>& operator<<(int n)调用成员函数。

If you always want to print a character, the safest and most clear option is:

如果你总是想打印一个字符,最安全和最明确的选择是:

std::cout << static_cast<signed char>(i);

And if you always want to print a number:

如果你总是想打印一个数字:

std::cout << static_cast<int>(i);

回答by Keith Thompson

int8_tis exactly 8 bits wide (if it exists).

int8_t正好是 8 位宽(如果存在)。

The only predefined integer types that can be 8 bits are char, unsigned char, and signed char. Both shortand unsigned shortare required to be at least 16 bits.

唯一预定义整数类型,可以是8位是charunsigned char,和signed char。二者shortunsigned short需要是至少16位。

So int8_tmust be a typedef for either signed charor plain char(the latter if plain charis signed).

所以int8_t必须是一个 typedef 或者是signed charplain char(如果plainchar是签名的,则后者)。

If you want to print an int8_tvalue as an integer rather than as a character, you can explicitly convert it to int.

如果要将int8_t值打印为整数而不是字符,则可以将其显式转换为int.

In principle, a C++ compiler could define an 8-bit extended integer type(perhaps called something like __int8), and make int8_ta typedef for it. The only reason I can think of to do so would be to avoid making int8_ta character type. I don't know of any C++ compilers that have actually done this.

原则上,C++ 编译器可以定义一个 8 位扩展整数类型(可能称为类似__int8),并int8_t为其创建typedef。我能想到的唯一原因是避免创建int8_t字符类型。我不知道有任何 C++ 编译器真正做到了这一点。

Both int8_tand extended integer types were introduced in C99. For C, there's no particular reason to define an 8-bit extended integer type when the chartypes are available.

无论int8_t和扩展整型是在C99推出。对于 C,当char类型可用时,没有特别的理由定义 8 位扩展整数类型。

UPDATE:

更新

I'm not entirely comfortable with this conclusion. int8_tand uint8_twere introduced in C99. In C, it doesn't particularly matter whether they're character types or not; there are no operations for which the distinction makes a real difference. (Even putc(), the lowest-level character output routine in standard C, takes the character to be printed as an intargument). int8_t, and uint8_t, if they're defined, will almost certainly be defined as character types -- but character types are just small integer types.

我对这个结论并不完全满意。int8_tuint8_t在 C99 中引入。在 C 中,它们是否是字符类型并不特别重要;没有任何操作的区别会产生真正的区别。(即使putc()是标准 C 中最低级别的字符输出例程,也将要打印的字符作为int参数)。int8_t, 和uint8_t,如果它们被定义,几乎肯定会被定义为字符类型——但字符类型只是小整数类型。

C++ provides specific overloaded versions of operator<<for char, signed char, and unsigned char, so that std::cout << 'A'and std::cout << 65produce very different output. Later, C++ adopted int8_tand uint8_t, but in such a way that, as in C, they're almost certainly character types. For most operations, this doesn't matter any more than it does in C, but for std::cout << ...it does make a difference, since this:

C++ 提供了operator<<for 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;

will probably print the letter Arather than the number 65.

可能会打印字母A而不是数字65

If you want consistent behavior, add a cast:

如果您想要一致的行为,请添加演员表:

uint8_t x = 65;
std::cout << int(x); // or static_cast<int>(x) if you prefer

I think the root of the problem is that there's something missing from the language: very narrow integer types that are not character types.

我认为问题的根源在于语言中缺少一些东西:不是字符类型的非常窄的整数类型。

As for the intent, I could speculate that the committee members either didn't think about the issue, or decided it wasn't worth addressing. One could argue (and I would) that the benefits of adding the [u]int*_ttypes to the standard outweighs the inconvenience of their rather odd behavior with std::cout << ....

至于意图,我可以推测委员会成员要么没有考虑这个问题,要么认为它不值得解决。有人可能会争辩说(我也会)将[u]int*_t类型添加到标准中的好处超过了它们在std::cout << ....

回答by Cassio Neri

I'll answer your questions in reverse order.

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

Does the standard specify whether this type can or will be a character type?

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

Short answer: int8_tis signed charin the most popular platforms (GCC/Intel/Clang on Linux and Visual Studio on Windows) but might be something else in others.

简短的回答int8_tsigned char最流行的平台(GCC /英特尔/锵在Linux和Visual Studio在Windows上),但可能会在其他别的东西。

The long answer follows.

长答案如下。

Section 18.4.1 of the C++11 Standard provides the synopsis of <cstdint>which includes the following

C++11 标准的第 18.4.1 节提供了概要<cstdint>,包括以下内容

typedefsigned integer typeint8_t; //optional

typedef有符号整数类型int8_t; //optional

Later in the same section, paragraph 2, it says

稍后在同一节的第 2 段中,它说

The header [<cstdint>] defines all functions, types, and macros the same as 7.18 in the C standard.

标头 [ <cstdint>] 定义了与C 标准中的7.18 相同的所有函数、类型和宏。

where C standard means C99 as per 1.1/2:

其中 C 标准是指按照 1.1/2 的 C99:

C ++ is a general purpose programming language based on the C programming language as described in ISO/IEC 9899:1999 Programming languages — C(hereinafter referred to as the C standard).

C++ 是一种基于 C 编程语言的通用编程语言,如ISO/IEC 9899:1999 编程语言 — C(以下简称C 标准)中所述。

Hence, the definition of int8_tis to be found in Section 7.18 of the C99 standard. More precisely, C99's Section 7.18.1.1 says

因此,int8_t可以在 C99 标准的第 7.18 节中找到的定义。更准确地说,C99 的第 7.18.1.1 节说

The typedefname intN_tdesignates a signed integer type with width N, no padding bits, and a two's complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits.

typedef名称intN_t指定具有宽度N、无填充位和二进制补码表示的有符号整数类型。因此,int8_t 表示宽度正好为 8 位的有符号整数类型

In addition, C99's Section 6.2.5/4 says

此外,C99 的第 6.2.5/4 节说

There are five standard signed integer types, designated as signed char, short int, int, long int, and long long int. (These and other types may be designated in several additional ways, as described in 6.7.2.) There may also be implementation-defined extended signed integer types. The standard and extended signed integer types are collectively called signed integer types.

有五种标准的有符号整数类型,指定为signed charshort intintlong intlong long int。(这些和其他类型可以通过几种额外的方式指定,如 6.7.2 中所述。)也可能存在实现定义的扩展有符号整数类型。该标准和整数类型扩展的有符号统称为整数类型的签署

Finally, C99's Section 5.2.4.2.1 imposes minimum sizes for standard signed integer types. Excluding signed char, all others are at least 16 bits long.

最后,C99 的第 5.2.4.2.1 节规定了标准有符号整数类型的最小大小。不包括signed char,所有其他人的长度至少为 16 位。

Therefore, int8_tis either signed charor an 8 bits long extended (non standard) signed integer type.

因此,int8_tsigned char或 8 位长扩展(非标准)有符号整数类型。

Both glibc (the GNU C library) and Visual Studio C library define int8_tas signed char. Intel and Clang, at least on Linux, also use libc and hence, the same applies to them. Therefore, in the most popular platforms int8_tis signed char.

glibc(GNU C 库)和 Visual Studio C 库都定义int8_tsigned char. Intel 和 Clang,至少在 Linux 上,也使用 libc,因此,这同样适用于它们。因此,在最流行的平台上int8_tsigned char.

Given this C++11 program, should I expect to see a number or a letter? Or not make expectations?

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

Short answer: In the most popular platforms (GCC/Intel/Clang on Linux and Visual Studio on Windows) you will certainly see the letter 'A'. In other platforms you might get see 65though. (Thanks to DyPfor pointing this out to me.)

简短回答:在最流行的平台(Linux 上的 GCC/Intel/Clang 和 Windows 上的 Visual Studio)中,您肯定会看到字母“A”。在其他平台上,您可能会看到65。(感谢DyP向我指出这一点。)

In the sequel, all references are to the C++11 standard (current draft, N3485).

在续集中,所有引用均参考 C++11 标准(当前草案,N3485)。

Section 27.4.1 provides the synopsis of <iostream>, in particular, it states the declaration of cout:

第 27.4.1 节提供了 的概要<iostream>,特别是,它声明了cout

extern ostream cout;

Now, ostreamis a typedeffor a template specialization of basic_ostreamas per Section 27.7.1:

现在,ostream是根据第 27.7.1 节typedef的模板basic_ostream特化:

template <class charT, class traits = char_traits<charT> >
class basic_ostream;

typedef basic_ostream<char> ostream;

Section 27.7.3.6.4 provides the following declaration:

第 27.7.3.6.4 节提供了以下声明:

template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c);

If int8_tis signed charthen it's this overload that's going to be called. The same section also specifies that the effect of this call is printing the character (not the number).

如果int8_t是,signed char则将调用此重载。同一部分还指定此调用的效果是打印字符(而不是数字)。

Now, let's consider the case where int8_tis an extended signed integer type. Obviously, the standard doesn't specify overloads of operator<<()for non standard types but thanks to promotions and convertions one of the provided overloads might accept the call. Indeed, intis at least 16 bits long and can represent all the values of int8_t. Then 4.5/1 gives that int8_tcan be promotedto int. On the other hand, 4.7/1 and 4.7/2 gives that int8_tcan be convertedto signed char. Finally, 13.3.3.1.1 yields that promotion is favored over convertion during overload resolution. Therefore, the following overload (declared in in 23.7.3.1)

现在,让我们考虑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);

basic_ostream& basic_ostream::operator<<(int n);

will be called. This means that, this code

将被调用。这意味着,这段代码

int8_t i = 65;
std::cout << i;

will print 65.

将打印65

Update:

更新:

1. Corrected the post following DyP's comment.

1. 更正了DyP评论后的帖子。

2. Added the following comments on the possibility of int8_tbe a typedeffor char.

2. 添加了以下关于int8_t成为typedeffor的可能性的评论char

As said, the C99 standard (Section 6.2.5/4 quoted above) defines 5 standard signed integer types (charis not one of them) and allows implementations to add their onw which are referred as non standard signed integer types. The C++ standard reinforces that definition in Section 3.9.1/2:

如上所述,C99 标准(上面引用的第 6.2.5/4 节)定义了 5 种标准有符号整数类型(char不是其中之一),并允许实现添加它们的 onw,它们被称为非标准有符号整数类型。C++ 标准加强了第 3.9.1/2 节中的定义:

There are five standard signed integer types : “signed char”, “short int”, “int”, “long int”, and “long long int” [...] There may also be implementation-defined extended signed integer types. The standard and extended signed integer types are collectively called signed integer types.

有五种标准的有符号整数类型:“signed char”、“short int”、“int”、“long int”和“long long int”[...] 也可能有实现定义的扩展有符号整数类型。标准的和扩展的有符号整数类型统称为有符号整数类型

Later, in the same section, paragraph 7 says:

后来,在同一节中,第 7 段说:

Types bool, char, char16_t, char32_t, wchar_t, and the signed and unsigned integer typesare collectively called integral types. A synonym for integral type is integer type.

类型boolcharchar16_tchar32_twchar_t和符号和无符号整数类型统称为整数类型整数类型的同义词是整数类型

Therefore, charis an integer type but charis neither a signed integer type nor an unsigned integer typeand Section 18.4.1 (quoted above) says that int8_t, when present, is a typedeffor a signed integer type.

因此,char是整数类型,但char既不是有符号整数类型也不是无符号整数类型,第 18.4.1 节(上面引用)说int8_t,当存在时,是typedef有符号整数类型的 a。

What might be confusing is that, depending on the implementation, charcan take the same values as a signed char. In particular, charmight have a sign but it's still not a signed char. This is explicitly said in Section 3.9.1/1:

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

[...] Plain char, signed char, and unsigned charare three distinct types. [...] In any particular implementation, a plain charobject can take on either the same values as a signed charor an unsigned char; which one is implementation-defined.

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

This also implies that charis nota signed integer type as defined by 3.9.1/2.

这也意味着,char通过3.9.1 / 2所定义的带符号的整数类型。

3. I admit that my interpretation and, specifically, the sentence "charis neither a signed integer type nor an unsigned integer type" is a bit controversial.

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

To strength my case, I would like to add that Stephan T. Lavavej said the very same thing hereand Johannes Schaub - litbalso used the same sentence in a comment on thispost.

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

回答by Rapptz

The working draft copy I have, N3376, specifies in [cstdint.syn] § 18.4.1 that the int types are typically typedefs.

我拥有的工作草案副本 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

Since the only requirement made is that it must be 8 bits, then typedef to a char is acceptable.

因为唯一的要求是它必须是 8 位,所以 typedef 到 char 是可以接受的。

回答by richselian

char/signed char/unsigned charare three different types, and a charis not always 8 bits. on most platform they are all 8-bits integer, but std::ostream only defined char version of >>for behaviors like scanf("%c", ...).

char/ signed char/unsigned char三种不同类型的,并且char不总是8位。在大多数平台上,它们都是 8 位整数,但 std::ostream 只定义>>了像scanf("%c", ...).