単一バイト精度でポインタ演算を移植可能に実行するにはどうすればよいですか?
それを念頭に置いて:
char
すべてのプラットフォームで 1 バイトではないsizeof(void) == 1
GCC の拡張機能としてのみ利用可能- 一部のプラットフォームではポインター deref ポインターのアラインメントに制限がある場合がありますが、算術演算には最小の基本 POD 型のサイズよりも細かい粒度が必要な場合があります。
単一バイト精度でポインタ演算を移植可能に実行するにはどうすればよいですか?
それを念頭に置いて:
char
すべてのプラットフォームで 1 バイトではないsizeof(void) == 1
GCC の拡張機能としてのみ利用可能あなたの仮定には欠陥があります -どこでも 1sizeof(char)
と定義されています。
C99 標準 (TC3)のセクション 6.5.3.4 (「sizeof 演算子」) から:
(パラグラフ2)
sizeof 演算子は、そのオペランドのサイズ (バイト単位) を生成します。これは、式または括弧で囲まれた型の名前の場合があります。
(パラグラフ3)
型 char、unsigned char、または signed char (またはその修飾バージョン) を持つオペランドに適用されると、結果は 1 になります。
これらをまとめると、C では、char のサイズに関係なく、そのサイズは「バイト」であることが明らかになります (特定のプラットフォームでは、8 ビットを超える場合でも)。
したがって、 Achar
は最小のアドレス可能な型です。a より小さい単位でアドレス指定する必要がある場合は、一度に a を読み取り、必要な部分をマスクするためにビット演算子を使用するchar
しかありません。char
char
sizeof(char)
1
C標準で保証されています。char
9 ビット以上を使用する場合でも。
したがって、次のことができます。
type *pt;
unsigned char *pc = (unsigned char *)pt;
そしてpc
算数に使います。 ただし、上記のキャストを使用してへの割り当ては、C 標準では未定義の動作です。pc
pt
char
が 8 ビット幅を超える場合、移植可能な (ANSI/ISO) C でバイト精度のポインター演算を行うことはできません。ここで、 byteとは、8 ビットを意味します。これは、基本型自体が 8 ビットより大きいためです。
標準によればchar
、データのアドレス指定可能な最小のチャンクです。より正確に対処することはできません-手動でパッキング/アンパッキングを行う必要があります。
ポインターを にキャストしますuintptr_t
。これは、ポインターのサイズである符号なし整数になります。次に、計算を行い、結果を逆参照する型のポインターにキャストします。
intptr_t
(署名されていることに注意してください。これは通常、あなたが望んでいるものではありません! 断るuintptr_t
正当な理由がない限り、固執する方が安全です!)
sizeof(void)
GCC の 1 で何を言おうとしているのか理解できません。型char
は理論的には複数の基になるマシン バイトで構成されている場合がありますが、C 言語sizeof(char)
では 1 であり、常に正確に 1 です。つまり、C 言語の観点からは、char
常に 1 "バイト" (マシン バイトではなく C バイト) です。 )。sizeof(void)
それを理解すれば、GCC で 1 であっても何の役にも立たないことも理解できます。GCC では、ポインターのポインター演算は、ポインターのポインター演算void *
とまったく同じように機能しますchar *
。つまり、一部のプラットフォームでchar *
機能しない場合は、機能しませんvoid *
。
一部のプラットフォームchar
オブジェクトが複数のマシン バイトで構成されている場合、完全なオブジェクトよりも小さい単位のメモリにアクセスする唯一の方法は、char
ビット演算を使用して完全なオブジェクトの必要な部分を「抽出」および「変更」することですchar
。C 言語では、 より小さいものに直接対処する方法はありませんchar
。繰り返しchar
ますが、常に C バイトです。
C99 標準では、1 バイト長の uint8_t が定義されています。コンパイラがこの型をサポートしていない場合は、typedef を使用して定義できます。もちろん、プラットフォームやコンパイラに応じて、異なる定義が必要になります。すべてをヘッダー ファイルにまとめて、あらゆる場所で使用します。