😎

std::byteできっちりバイト生活

2025/01/18に公開
2

C++で特定のバイト数のメモリを確保したい時は、昔からcharunsigned charという型を使っていると思います。

例えば、以下のようにちょうど20バイトのメモリを確保できます。

char* buffer = new char[20];

でもこれはcharunsigned char型の変数のサイズがどのコンパイラーでもちょうど 1 バイトなので、そうしているだけであって、上のコードを見ると、bufferを実際に 20 バイトのメモリとして使いたいのか、それとも20個の文字が入る文字列として使いたいのか、型だけでは分からないです。

本来はcharunsigned charは整数型なのですが、文字として使われる型でもあるので、使い道が色々ある型になっています。なので、メモリとして使う時も、文字としても数字としても使えてしまいます。要するに間違った使い方も簡単にできてしまいます。

前に紹介したように、こういう一般的な型より、専用の strong 型の方がお勧めです。そのため、特定のバイト数のメモリが使いたい場合のために、C++ 17 からバイト専用の型std::byteが追加されました。

#include <cstddef>

std::byte* buffer = new std::byte[20];

↑のコードだと「20 バイトのメモリが欲しい」ってことはすぐ読み取れます。また、std::byteにはキャスト関数以外、ビット計算用の演算子と比較演算子しか定義されていないため、うっかり間違った使い方をしてしまう恐れはないです。

bufferの中身にアクセスする時は、std::byteとしてそのままアクセスするか、使いたい型へキャストしてからアクセスすることになります。

バイトを1つずつキャストする場合は、以下のように用意されているstd::to_integer<T>(std::byte)という関数を使うのがお勧めです。

char first = std::to_integer<char>(buffer[0]);
int second = std::to_integer<int>(buffer[0]);

纏めてキャストしたい場合は、std::reinterpret_castを使いましょう。

char* buffers_as_char = reinterpret_cast<char*>(buffer);
char* buffer_as_int = reinterpret_cast<int*>(buffer);

昔から C++ を使っている人は、別に今まで通りcharunsigned charでいいじゃんってなるかもしれないです。まあ、それもそうです。動作的にはあんまり違いはないですし、既存のcharunsigned charを使っているコードをわざわざ変えたくないのも分かります。

でもこれから書く新しいコードを読みやすくて分かりやすくしたい人には、std::byteを是非使ってみて欲しいです。


|cpp記事一覧へのリンク|

Discussion

yaito3014yaito3014

ポインタ同士の変換について、 void* との変換以外では static_cast ではなく reinterpret_cast が必要になると思います。