2

4 つの異なる文字に分割する必要がある 4 バイトの DWORD があります。これを達成する方法を知っていると思っていましたが、毎回奇妙な数字が得られます。これが私のコードです:

    // The color memory
    int32 col = color_mem[i];

    // The four destination characters
    char r, g, b, a;

    // Copy them in advancing by one byte every time
    memcpy(&r, &col, 1);
    memcpy(&g, &col + 1, 1);
    memcpy(&b, &col + 2, 1);
    memcpy(&a, &col + 3, 1);
4

5 に答える 5

10

を捨ててmemcpy、ビット操作を使用します。

r = (col & 0x000000ff);
g = (col & 0x0000ff00) >>  8;
b = (col & 0x00ff0000) >> 16;
a = (col & 0xff000000) >> 24;

ff16 進数の は、すべての1ビットのバイトを表します。これと&- ビットごとの AND - は、関心のないバイトを各位置で作成し、0関心のあるビットを保持します。

実際の>>割り当てのために、必要なバイトを最上位の位置に置き、左からゼロにシフトします。8 のシフトは 1 バイトの幅でシフトし、16 は 2 バイト、24 は 3 バイトです。

を視覚的に見るとff、バイト インデックスを左に向かって歩いていることが想像できます。

于 2012-08-09T22:47:20.720 に答える
4

ポインター演算を行う場合、インクリメントまたはデクリメントの量は、ポイントされている型のサイズで乗算されます。のベースアドレスからオフセットされたサイズのパーツにアクセスするためにint32、ポインターをポインターにキャストします。charcharcol

この手法は、プラットフォームごとのエンディアンの違いにより脆弱になる可能性があるため、別の回答で提供されている、より移植性の高いビットマスク操作を使用することをお勧めします。

// The color memory  
int32 col = color_mem[i];  

// The four destination characters  
char r, g, b, a;  

// Copy them in advancing by one byte every time  
memcpy(&r, (char*)&col, 1);  
memcpy(&g, ((char*)&col) + 1, 1);  
memcpy(&b, ((char*)&col) + 2, 1);  
memcpy(&a, ((char*)&col) + 3, 1); 
于 2012-08-09T22:50:31.597 に答える
2

int32 に +1 を追加すると、アドレスが 4 バイト上がります。

などを使用できますmemcpy(&g, reinterpret_cast<char *>(&col)+1, 1)

より良い方法:

int32 col = color_mem[i];

struct splitted4byte
{
    char r;
    char g;
    char b;
    char a;
}

splitted4byte rgb;

memcpy(&rgb, &col, 4);

ところで、バイトの順序に注意する必要がありますcol。int32 のどの部分がどの色かわかりません。

エンディアンについて読む必要があります。(ググってください、ドキュメントがあります)

R の最大値と他の色が 0 の場合、それが として格納されている1111 1111 0000 0000 0000 0000 0000 0000場合、色 RGBA(255,0,0,0) の整数表現がこのバイナリ値に等しいかどうかを意味します。メモリ内では逆順になる0000 0000 0000 0000 0000 0000 1111 1111ため、これを計算する必要があります。

ネットワーク バイト オーダー (ビッグ エンディアン) をホスト マシンのバイト オーダー (リトル エンディアンまたはビッグ エンディアン) に変換するネットワーク変換関数を使用できます。これにより、マシンに応じてコードを変更する必要がなくなります。(関数は ntohl (ネットワークからホストへの長い) であり、2 バイトには htons (ホストからネットワークへの短い) などもあり、64 ビット整数には be64toh() もありますが、関数は Unix バリアントでのみ終了します。私は正しく覚えています。)あなたがする必要があるのは、int32 col = ntohl(color_mem[i]);

または、これに従って構造体の順序を作成することもできますが、その方法では、コードはビッグエンディアンでは機能しません。

于 2012-08-09T22:51:41.480 に答える
1

col は int32 +1 であるため、4 バイトのオフセットが追加されます

Google でポインター演算を検索する

于 2012-08-09T22:50:46.100 に答える
1

誰もが異なる答えを与えられており、すべてが何らかの形で正しい. エンディアン固有のものもあります (ビット演算を行う場合など)。他の人はそうではありません。明確にするために、私はこれを行うかもしれません:

char *bytes = (char*)&color_mem[i];
char r = bytes[0];
char g = bytes[1];
char b = bytes[2];
char a = bytes[3];

を使用する理由がわかりませんmemcpy。構造物でも。構造割り当ては言語機能です。コピーする必要はありません。

労働組合についての言及はまだ見たことがありません...

union Pixel {
    DWORD packed;
    struct Components {
        char r, g, b, a;
    };
    char bytes[4];
};

// You can just specify your image data like this...
Pixel *pixels = (Pixel*)color_mem;

// Reference one pixel for convenience - don't need to reference, you can
// just copy it instead if you want (alternative: Pixel p = pixels[i])
Pixel &p = pixels[i];

char r = p.r;
char g = p.g;
char b = p.b;
char a = p.a;

int32 col = p.packed;

これはエンディアン中立です: 整数の編成に依存しません。通常はこれで問題ありませんが、それでも意識する必要があります。

于 2012-08-09T23:16:21.070 に答える