1

こんにちは、ここに 7 バイトの構造体があり、それを 64 ビット整数に書き込みたいと思います。次に、後でこの構造体を 64 ビット整数から抽出したいと思います。

これに関するアイデアはありますか?

#include "stdafx.h"

struct myStruct
{
        unsigned char a;               
        unsigned char b;
        unsigned char b;
        unsigned int someNumber;
};

int _tmain(int argc, _TCHAR* argv[])
{
    myStruct * m = new myStruct();
    m->a = 11;
    m->b = 8;
    m->c = 12;
    m->someNumber = 30;

    printf("\n%s\t\t%i\t%i\t%i\t%i\n\n", "struct", m->a, m->b, m->c, m->someNumber);

    unsigned long num = 0;

    // todo: use bitwise operations from m into num (total of 7 bytes) 

    printf("%s\t\t%i\n\n", "ulong", num);

    m = new myStruct();

    // todo: use bitwise operations from num into m;

    printf("%s\t\t%i\t%i\t%i\t%i\n\n", "struct", m->a, m->b, m->c, m->someNumber);

    return 0;
}
4

3 に答える 3

1

次のようにする必要があります。

class structured_uint64
{
    uint64_t data;
public:
    structured_uint64(uint64_t x = 0):data(x) {}
    operator uint64_t&() { return data; }
    unsigned uint8_t low_byte(size_t n) const { return data >> (n * 8); }
    void low_byte(size_t n, uint8_t val) {
        uint64_t mask = static_cast<uint64_t>(0xff) << (8 * n);
        data = (data & ~mask) | (static_cast<uint64_t>(val) << (8 * n));
    }
    unsigned uint32_t hi_word() const { return (data >> 24); }
    // et cetera
};

(もちろん、インターフェイスの詳細と、構成要素が 64 ビットのどこに配置されるかについては、バリエーションの余地がたくさんあります)

異なるタイプを使用してメモリの同じ部分にエイリアスを設定することは、一般的に悪い考えです。問題は、オプティマイザーが次のような推論を使用できることは非常に価値があるということです。

「わかりました。uint64_tこのブロックの先頭で a を読み取りましたが、途中でプログラムがuint64_ts に書き込む場所はありません。したがって、値は変更されていないはずです!」

uint64_tつまり、参照によってオブジェクトの値を変更しようとすると、間違った答えが得られますuint32_t。そして、これはどのような最適化が可能で実行されるかに大きく依存するため、実際には、テスト ケースで問題に出くわすことはありませんが、作成しようとしている実際のプログラムで問題を確認するのは非常に簡単です。バグを見つけるのは、この問題ではないと確信しているからです。

そのため、巧妙な構造体を設定しようとするのではなく、フィールドの挿入/抽出をビット操作 (またはプロファイリングでこれがパフォーマンスの問題であり、有用な問題があることが示されている場合は組み込み関数) を使用して実行する必要があります。

自分が何をしているのかを本当に知っているなら、エイリアシングを機能させることができると私は信じています。しかし、それは自分が何をしているのかを本当に理解している場合にのみ行うべきであり、それには、標準の内外から関連するルールを知っていることが含まれます (私は知らないので、それを機能させる方法についてアドバイスすることはできません)。 . それでも、おそらくそれを行うべきではありません。

また、整数型を特定のサイズにする場合は、正しい型を使用する必要があります。たとえば、unsigned int正確に 32 ビットであると想定される整数には決して使用しないでください。代わりに を使用しますuint32_t。自己文書化されているだけでなく、 32 ビット以外の環境でプログラムをビルドしようとしても、不快な驚きに遭遇することunsigned intはありません。

于 2012-06-15T08:44:56.120 に答える
0

とった。

static unsigned long long compress(char a, char b, char c, unsigned int someNumber)
{
    unsigned long long x = 0;
    x = x | a;
    x = x << 8;
    x = x | b;
    x = x << 8;
    x = x | c;
    x = x << 32;
    x = x | someNumber;
    return x;
}

myStruct * decompress(unsigned long long x)
{
    printBinary(x);
    myStruct * m = new myStruct();
    m->someNumber = x | 4294967296;
    x = x >> 32;
    m->c = x | 256;
    x = x >> 8;
    m->b = x | 256;
    x = x >> 8;
    m->a = x | 256;
    return m;
}
于 2012-06-15T20:55:50.467 に答える
0

を使用しunionます。a の各要素はunion、同じアドレス空間を占有します。structは 1 つの要素であり、unsigned long longは別の要素です。

#include <stdio.h>

union data
{
    struct
    {
        unsigned char a;
        unsigned char b;
        unsigned char c;
        unsigned int d;
    } e;
    unsigned long long f;
};

int main()
{
    data dat;
    dat.f = 0xFFFFFFFFFFFFFFFF;
    dat.e.a = 1;
    dat.e.b = 2;
    dat.e.c = 3;
    dat.e.d = 4;
    printf("f=%016llX\n",dat.f);
    printf("%02X %02X %02X %08X\n",dat.e.a,dat.e.b,dat.e.c,dat.e.d);
    return 0;
}

出力しますが、元の 1 バイトがunsigned long long残ることに注意してください。コンパイラは、4 で割り切れるアドレス上の 4 バイト整数などのデータを整列することを好みます。したがって、3 バイト、次にパッド バイトを配置して、整数がオフセット 4 にありstruct、合計サイズが 8 になるようにします。

f=00000004FF030201
01 02 03 00000004

これは、コンパイラに依存する方法で制御できます。以下は Microsoft C++ の場合です。

#include <stdio.h>

#pragma pack(push,1)
union data
{
    struct
    {
        unsigned char a;
        unsigned char b;
        unsigned char c;
        unsigned int d;
    } e;
    unsigned long long f;
};
#pragma pack(pop)

int main()
{
    data dat;
    dat.f = 0xFFFFFFFFFFFFFFFF;
    dat.e.a = 1;
    dat.e.b = 2;
    dat.e.c = 3;
    dat.e.d = 4;
    printf("f=%016llX\n",dat.f);
    printf("%02X %02X %02X %08X\n",dat.e.a,dat.e.b,dat.e.c,dat.e.d);
    return 0;
}

structは現在 7 バイトを占めており、最上位バイトはunsigned long long変更されていないことに注意してください。

f=FF00000004030201
01 02 03 00000004
于 2012-06-15T06:29:23.900 に答える