現在、バイナリ データを扱う必要がある場合があります。C++ では、一連のバイトを扱います。最初から、char
ビルディング ブロックでした。1を持つように定義されたsizeof
、それはバイトです。また、すべてのライブラリ I/O 関数はchar
デフォルトで使用します。すべては問題ありませんが、常に少しの懸念がありました。一部の人々を悩ませた少し奇妙な点です。1 バイトのビット数は処理系で定義されています。
そのため、C99 では、開発者が固定幅整数型を簡単に表現できるように、いくつかの typedef を導入することが決定されました。もちろん、可搬性を損なうことは絶対にしたくないので、オプションです。その中で、固定幅の 8 ビット符号なし整数型uint8_t
として C++11 に移行されstd::uint8_t
た は、8 ビット バイトを本当に処理したい人にとって最適な選択でした。
std::uint8_t*
そのため、開発者は新しいツールを採用し、8 ビットのバイト シーケンスをstd::vector<std::uint8_t>
やその他の形式で受け入れることを明示的に示すライブラリの構築を開始しました。
しかし、おそらく非常に深く考えて、標準化委員会は の実装を要求しないことを決定したため、開発者がs をバイナリ データとしてstd::char_traits<std::uint8_t>
簡単かつ移植可能にインスタンス化したりstd::basic_fstream<std::uint8_t>
、簡単に読み取ったりすることを禁止しました。std::uint8_t
あるいは、1 バイトのビット数を気にせず、満足している人もいます。
char*
しかし、残念なことに、2 つの世界が衝突し、データを as として取得し、それを期待するライブラリに渡さなければならない場合がありますstd::uint8_t*
。でもちょっと待って、char
可変ビットじゃなくstd::uint8_t
て8固定じゃないの?データが失われますか?
さて、これについて興味深い標準があります。はchar
正確に 1 バイトを保持するように定義されており、バイトはメモリのアドレス指定可能な最小のチャンクであるため、ビット幅が のビット幅よりも小さい型は存在できませんchar
。次に、UTF-8 コード単位を保持できるように定義されています。これにより、最小値である 8 ビットが得られます。これで、8 ビット幅である必要がある typedef と、少なくとも 8 ビット幅の型ができました。しかし、代替手段はありますか?はいunsigned char
。char
の署名は実装定義であることを思い出してください。他のタイプは?ありがたいことに、いいえ。他のすべての整数型には、8 ビット外の範囲が必要です。
最後に、std::uint8_t
オプションです。つまり、この型を使用するライブラリは、定義されていないとコンパイルされません。しかし、それがコンパイルされるとどうなるでしょうか? これは、8 ビット バイトとCHAR_BIT == 8
.
8 ビットのバイトがあり、 または のいずれかとして実装されているというこの知識をstd::uint8_t
得たら、 からへ、またはその逆を行うことができると仮定できますか? ポータブルですか?char
unsigned char
reinterpret_cast
char*
std::uint8_t*
これは、私の標準語の読解力が私を失敗させるところです。私は安全に派生したポインター ( [basic.stc.dynamic.safety]
) について読み、私が理解している限り、次のことを読みました。
std::uint8_t* buffer = /* ... */ ;
char* buffer2 = reinterpret_cast<char*>(buffer);
std::uint8_t buffer3 = reinterpret_cast<std::uint8_t*>(buffer2);
触れなければ安全ですbuffer2
。私が間違っている場合は修正してください。
したがって、次の前提条件が与えられます。
CHAR_BIT == 8
std::uint8_t
が定義されています。
バイナリデータを扱っていて、潜在的な符号の欠如が問題にならないと仮定すると、移植性があり、前後にキャストchar*
しても安全ですか?std::uint8_t*
char
説明付きの標準への参照をいただければ幸いです。
編集: ありがとう、ジェリー コフィン。標準 ([basic.lval]、§3.10/10) からの引用を追加します。
プログラムが、次の型以外の glvalue を介してオブジェクトの格納された値にアクセスしようとした場合、動作は未定義です。
...
— char または unsigned char 型。
EDIT2:わかりました、さらに深くなります。std::uint8_t
の typedef であることは保証されませんunsigned char
。拡張符号なし整数型として実装でき、拡張符号なし整数型は §3.10/10 に含まれていません。今何?