このC++ 11プログラムが与えられた場合、数字または文字が表示されるはずです。または期待しないでください?
#include <cstdint>
#include <iostream>
int main()
{
int8_t i = 65;
std::cout << i;
}
標準では、このタイプが文字タイプであるかどうかを指定していますか?
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]の状態:
5つの標準符号付き整数型があります:「_
signed char
_」、「_short int
_」、「int
」 、「_long int
_」、「_long long int
_」。このリストでは、各タイプは少なくともリスト内でその前にあるストレージと同じくらいのストレージを提供します。実装定義拡張符号付き整数型もあります。標準および拡張符号付き整数型は、符号付き整数型と総称されます。...
タイプ
bool
、char
、_char16_t
_、_char32_t
_、_wchar_t
_、および符号付きおよび符号なし整数型はまとめて呼び出されます整数型。整数型の同義語は、整数型です。
§3.9.1は次のようにも述べています。
特定の実装では、プレーンな
char
オブジェクトは_signed char
_または_unsigned char
_と同じ値を取ることができます。どちらが実装定義です。
_int8_t
_は、char
オブジェクトが符号付きの値を取る場合、char
のtypedefであると結論付けるのは魅力的です。ただし、char
は符号付き整数型(標準および場合によっては拡張符号付き整数型)のリストに含まれないため、これは当てはまりません。 Stephan T. Lavavejのコメント on _std::make_unsigned
_および_std::make_signed
_も参照してください。
したがって、_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]を参照して以下を決定します。
int8_t
_が_signed char
_の完全一致(つまり、_signed char
_のtypedef)の場合、template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, signed char)
テンプレートが呼び出されます。int8_t
_がint
に昇格され、basic_ostream<charT,traits>& operator<<(int n)
メンバー関数が呼び出されます。u
の_std::cout << u
_の場合_uint8_t
_オブジェクト:
uint8_t
_が_unsigned char
_に完全一致する場合、template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, unsigned char)
テンプレートが呼び出されます。int
はすべての_uint8_t
_値を表すことができるため、_uint8_t
_はint
に昇格され、basic_ostream<charT,traits>& operator<<(int n)
メンバー関数が呼び出されます。常に文字を印刷したい場合、最も安全で最も明確なオプションは次のとおりです。
_std::cout << static_cast<signed char>(i);
_
そして、常に数字を印刷したい場合:
_std::cout << static_cast<int>(i);
_
_int8_t
_は正確に8ビット幅です(存在する場合)。
8ビットにすることができる定義済みの整数型は、char
、_unsigned char
_、および_signed char
_のみです。 short
と_unsigned short
_の両方が少なくとも16ビットである必要があります。
したがって、_int8_t
_は、_signed char
_またはプレーンchar
(プレーンchar
が署名されている場合は後者)のいずれかのtypedefでなければなりません。
_int8_t
_値を文字としてではなく整数として出力する場合、int
に明示的に変換できます。
原則として、C++コンパイラは、8ビット拡張整数型(おそらく___int8
_のようなものと呼ばれる)を定義し、_int8_t
_そのtypedef。私がそうすることを考えることができる唯一の理由は、_int8_t
_を文字型にすることを避けるためです。実際にこれを行ったC++コンパイラは知りません。
_int8_t
_と拡張整数型の両方がC99で導入されました。 Cの場合、char
型が使用可能なときに8ビット拡張整数型を定義する特別な理由はありません。
[〜#〜] update [〜#〜]:
私はこの結論に完全には満足していません。 _int8_t
_および_uint8_t
_はC99で導入されました。 Cでは、文字タイプかどうかは特に関係ありません。区別が実際の違いを生む操作はありません。 (標準Cの最低レベルの文字出力ルーチンであるputc()
でさえ、int
引数として印刷される文字を取ります)。 _int8_t
_、および_uint8_t
_は、定義されている場合、ほぼ確実に文字型として定義されますが、文字型は単なる小さな整数型です。
C++は、char
、_operator<<
_、および_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;
_
おそらく、番号_65
_ではなく、文字A
を出力します。
一貫した動作が必要な場合は、キャストを追加します。
_uint8_t x = 65;
std::cout << int(x); // or static_cast<int>(x) if you prefer
_
問題の根本は、言語に欠けているものがあることだと思います。文字型ではない非常に狭い整数型です。
意図については、委員会のメンバーが問題について考えなかったか、対処する価値がないと判断したと推測できます。 _[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では、
ヘッダー[_
<cstdint>
_]は、C標準の7.18と同じすべての関数、型、およびマクロを定義します。
c標準は1.1/2によるC99を意味します:
C++は、ISO/IEC 9899:1999プログラミング言語— C(以下で参照)で説明されているCプログラミング言語に基づいた汎用プログラミング言語です。 C標準として)。
したがって、_int8_t
_の定義は、C99標準のセクション7.18にあります。より正確には、C99のセクション7.18.1.1には
typedef
name _intN_t
_は、幅N
、パディングビットなし、2の補数表現を持つ符号付き整数型を指定します。したがって、int8_tは、正確に8ビットの幅を持つ符号付き整数型を示します。
さらに、C99のセクション6.2.5/4には、
5つの標準符号付き整数型があり、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
_として定義します。少なくともLinuxではIntelとClangも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;
_
現在、ostream
は、セクション27.7.1による_basic_ostream
_のテンプレート特化のtypedef
です。
_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<<()
のオーバーロードを指定していませんが、プロモーションと変換のおかげで、提供されたオーバーロードの1つが呼び出しを受け入れる可能性があります。実際、int
は少なくとも16ビット長で、_int8_t
_のすべての値を表すことができます。次に、4.5/1は_int8_t
_をpromoted to int
にできることを示します。一方、4.7/1および4.7/2では、_int8_t
_をconverted to _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;
_
_65
_を出力します。
更新:
1。 DyP のコメントに続く投稿を修正しました。
2。 _int8_t
_がtypedef
のchar
になる可能性に関する次のコメントを追加しました。
前述のように、C99標準(上記のセクション6.2.5/4)は5つの標準符号付き整数型を定義し(char
はそれらの1つではありません)、実装が非標準符号付き整数と呼ばれるonwを追加できるようにしますタイプ。 C++標準は、セクション3.9.1/2のその定義を強化します。
「signed char」、「short int」、「int」、「long int」、「long long int」の5つの標準符号付き整数型があります[...]実装定義の拡張符号付き整数型もあります。標準および拡張符号付き整数型は、符号付き整数型と総称されます。
後で、同じセクションで、パラグラフ7に次のように記載されています。
タイプ
bool
、char
、_char16_t
_、_char32_t
_、_wchar_t
_、および符号付きおよび符号なし整数型は統合型と総称されます。整数型の同義語は、整数型です。
したがって、char
は整数型ですが、char
は符号付き整数型でも符号なし整数型でもありませんおよびセクション18.4.1(上記で引用)は、_int8_t
_が存在する場合、符号付き整数型のtypedef
であることを示しています。
紛らわしいのは、実装によっては、char
が_signed char
_と同じ値をとることがあることです。特に、char
には符号が付いている場合がありますが、_signed char
_ではありません。これは、セクション3.9.1/1で明示的に述べられています。
[...]プレーン
char
、_signed char
_、および_unsigned char
_は、3つの異なるタイプです。 [...]特定の実装では、プレーンchar
オブジェクトは_signed char
_または_unsigned char
_と同じ値を取ることができます。どちらが実装定義です。
これは、char
がnot3.9.1/2で定義されている符号付き整数型であることも意味します。
3。私の解釈と、具体的には、「char
は符号付き整数型でも符号なし整数型でもない」という文は少し議論の余地があることを認めます。
私の主張を強めるために、ステファン・T・ラヴァヴェージが同じことを言ったことを付け加えたいと思います here と Johannes Schaub-litb もコメントで同じ文を使用しました- this post。
私が持っている作業ドラフトのコピー、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に対するtypedefは許容されます。