2017-07-06 9 views
-1

バイト配列にシリアライズされたデータをデバッグする方法を理解しようとしています。このコードでは、ソリューションの試用が失敗した場合の問題を取り除いています。バイト配列へのキャスト後の値の印刷

私が達成しようとしているのは、配列全体のメンバー12345678の印刷物をちょうど78にすることです。

#include <stdio.h> 
#include <stdint.h> 
#include <inttypes.h> 

int main() 
{ 
    uint32_t words[2] = {0x12345678, 0x87654321}; 
    char * struct_array = &words; 

    printf("%x \n", *struct_array); // 78 prints a lsb byte from the first array member 
    printf("%lx \n", *struct_array); // 78 assuming it would print more than a single byte 

    //Perhaps it's printing a single byte because of the char pointer. 
    printf("%x \n", (uint32_t) *struct_array); // 78 
    printf("%lx \n", (uint32_t) *struct_array); // 78 
    // Nope 
} 

答えて

2

この:

char * struct_array = &words; 

charへのポインタにstruct_arrayになります。参照を外すとcharとなり、の後にはの後に変更することはできません。

することはできコース(しかしリスク未定義の動作)を逆参照する前にポインタをキャスト:

printf("%x\n", *(uint32_t *) struct_array); 

それが適切なデシリアライズコードを使用すると、ブルートフォースをするためにそれをポインタでしようとしないし、もちろん良いでしょう逆参照トリッキー。あなたが知っているバイト数が大きい場合は、それをまとめてください。これは実際のバイト配列されていた場合

は、最後の点に展開するには:

const uint8_t data[] = { 0x78, 0x56, 0x34, 0x12 }; 

、あなたはリトルエンディアンストレージあなたを想定し、32ビットの符号なし整数にそれらを再び組み立ててみたかったですやるD」:

const uint32_t x = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); 
printf("x de-serialized into 0x%08x\n", x); 

何も違反することなくx de-serialized into 0x12345678を印刷し、そしてこのすべてのだろう。 :)

+0

'あなたが知っているバイト数が多い場合は、それをまとめてください.'与えられた例の意味は? – TheMeaningfulEngineer

+0

@TheMeaningfulEngineerその点をより詳細に示すコードが追加されました。 – unwind

+0

@unwindこのデシリアライズ方法は、エンディアンに依存しません。しかし、 'data [n]'は 'int'にキャストされるので、' data [3] << 24'で符号付き整数オーバーフローが発生する可能性があります。 – Aconcagua

1
//expected it would print more than a single byte 

という予想が間違っています。逆参照は既に行われており、その時点でstruct_arraychar *であった。値(昇格された)は、変換指定子の引数として使用されます。

与えられた引数の型と変換指定子が内部的にはのように内部的に関係していないことを強調しておきますが、これはプログラマの仕事です。

元の型としてバッファに元の値を生成させる場合は、キャストを使用してポインタを実際の型に変更し、逆参照して値を取得する必要があります。逆参照の後、キャストはここでは意味がありません。

注意:厳密なエイリアシングを壊す「any」以外のタイプだけでなく、元のタイプまたは互換性のあるタイプにポインタをキャストすることができます

+0

DVの理由は? –

+0

真剣にも、これは答えではなく、コメントです。質問が明確でない場合は、VtCに不明な点を記入してください。 – Olaf

+0

@Olaf OK ... _expectation_の問題だと思った。 _longer_幅の変換指定子を指定するか、値をキャストしようとすると参照外に_bytes_が増えません。 –

2

struct_arrayは、タイプchar*です。 e。 charへのポインタ*struct_arrayは、単一のchar(1バイト)にデリファレンスされるため、メモリ内の最初のバイトだけがwordsで占められます。明らかにあなたのマシンはリトルエンディアンなので、データは逆のバイト順で格納されるので、0x78が得られます。 charuint32_tにキャストしても、その値は変更されません。値は0x78、32ビット整数に収まるため、0x78のままです。

値全体を取得する場合は、値全体を読み取る必要があります。 e。あなたはそれを逆参照する前にポインタをキャストする必要があることを意味し、uint32_tへのポインタを参照解除:

*(uint32_t*)struct_array 
+0

'*(uint32_t *)struct_array'は残念なことに厳密なエイリアシング違反です。 – Lundin

+2

@ Lundinどのように? – Aconcagua

+0

@Lundin 'struct_array'は' char * 'なので、厳密なエイリアシング規則は適用されません。これは、元のアドレスを持つ元の型にキャストしているだけです。 –