7

私はこのような配列を持っています:

unsigned char array[] = {'\xc0', '\x3f', '\x0e', '\x54', '\xe5', '\x20'};
unsigned char array2[6];

memcpyを使用する場合:

memcpy(array2, array, 6);

そして、それらの両方を印刷します。

printf("%x %x %x %x %x %x", array[0],  // ... etc
printf("%x %x %x %x %x %x", array2[0], // ... etc

1つは次のように印刷します:

c0 3f e 54 e5 20

しかし、もう一方は印刷します

ffffffc0 3f e 54 ffffffe5 20

どうした?

4

4 に答える 4

13

私はあなたのコードを完全にコンパイル可能な例に変えました。charまた、環境上で署名されている「通常」の3番目の配列を追加しました。

#include <cstring>
#include <cstdio>

using std::memcpy;
using std::printf;

int main()
{

        unsigned char array[] = {'\xc0', '\x3f', '\x0e', '\x54', '\xe5', '\x20'};
        unsigned char array2[6];
        char array3[6];

        memcpy(array2, array, 6);
        memcpy(array3, array, 6);

        printf("%x %x %x %x %x %x\n", array[0], array[1], array[2], array[3], array[4], array[5]);
        printf("%x %x %x %x %x %x\n", array2[0], array2[1], array2[2], array2[3], array2[4], array2[5]);
        printf("%x %x %x %x %x %x\n", array3[0], array3[1], array3[2], array3[3], array3[4], array3[5]);

        return 0;
}

私の結果は私が期待したものでした。

c0 3f e 54 e5 20
c0 3f e 54 e5 20
ffffffc0 3f e 54 ffffffe5 20

ご覧のとおり、配列がsigned char型の場合にのみ、「extra」ffが追加されます。その理由はmemcpy、signedの配列にデータを入力するcharと、上位ビットが設定された値が負のchar値に対応するようになったためです。に渡されるとprintf、タイプにcharプロモートされintます。これは、事実上、符号拡張を意味します。

%xのように16進数で出力しますが、動作が技術的に定義されていないunsigned intため、引数が渡されたためです。int通常、2の補数マシンでは、動作はmod 2 ^ N演算を使用する標準の符号付きから符号なしへの変換と同じです(ここで、Nはの値ビット数ですunsigned int)。値は「わずかに」負(狭い符号付きタイプからのもの)であったため、変換後の値は可能な最大値に近くなりunsigned intます。つまり、多くの先行値1(2進数)または先頭fが16進数になります。

于 2010-08-18T14:00:28.837 に答える
5

問題はそうではありませんmemcpy(charタイプが実際には8ビットではなく32ビットでない限り)、印刷中の整数符号拡張のように見えます。

unsignedchar変換を明示的に使用するようにprintfを変更することもできます。

printf("%hhx %hhx...", array2[0], array2[1],...);

推測として、コンパイラ/オプティマイザが処理していてarray(サイズと内容はコンパイル時にわかっている)array2、最初に定数値をスタックにプッシュし、次に誤って符号拡張値をプッシュしている可能性があります。

于 2010-08-18T13:55:50.397 に答える
4

intvarargs関数を呼び出すと、charがサイズに拡張されるため、上位ビットをマスクする必要があります。

printf("%x %x %x %x %x %x", array[0] & 0xff,  // ..
于 2010-08-18T13:56:17.880 に答える
2

%x形式は整数型を想定しています。キャスティングを使用してみてください:

printf( "%x%x%x%x%x%x"、(int)array2 [0]、..。

編集:私の投稿に新しいコメントがあるので、いくつかの情報を追加したいと思います。printf関数を呼び出す前に、コンパイラーはパラメーターのスタック変数リスト(...)をプッシュするコードを生成します。コンパイラはprintfフォーマットコードについて何も知らず、そのタイプに従ってパラメータをプッシュします。printfは、フォーマット文字列に従ってスタックからパラメータを収集します。したがって、array [i]はcharとしてプッシュされ、printfによってintとして処理されます。したがって、パラメータタイプがフォーマット仕様と正確に一致しない場合は、printf / scanf関数を使用して、キャストを作成することをお勧めします。

于 2010-08-18T13:54:02.897 に答える