0

大きなblob(割り当てられたメモリ)を使用して、データをメモリに継続的に保存しています。

BLOB内のデータを次のように整理する必要があります。

| data1タイプ| data1 | data2タイプ| data2 | dataNタイプ| dataN |

dataN typeを適切なタイプintに変換するためにスイッチで使用するものです。dataN

問題は、データを適切に整列させたいので、blob内のすべてのデータを8バイトパックするように強制したいことです(おそらくデータを適切に整列させておくため、パッキングに8バイトを選択しましたか?)。密集しています(整列のため、データ->データ型の間に穴はありません)。

私はこれを試しました:

#pragma pack(8)
class A
{
public:
    short b;
    int x;
    char v;
};

sizeof(A)しかし、使用すると、予想される16バイトではなく12バイトになるため、機能しません。

PS:x86またはx64アーキテクチャのいずれかに8バイトを超えるデータ型はありますか?

4

4 に答える 4

1

この場合#pragma pack(8)、効果がないようです。

MSコンパイラのドキュメントでは、packのパラメータは次のように記述されています。パッキングに使用される値をバイト単位で指定します。nのデフォルト値は8です。有効な値は1、2、4、8、および16です。メンバーの配置は、 nの倍数またはメンバーのサイズの倍数のいずれかである境界上になります。小さいです。

したがって、#pragma packディレクティブはメンバーの配置を増やすことはできませんが、(#pragma pack(1)たとえばを使用して)減らすことができます。この場合、構造全体のアラインメントは、最大の要素が自然にアラインメントされるように選択されます(int通常、32ビットCPUと64ビットCPUの両方で4バイトです)。その結果、合計サイズは4 * 3=12バイトになります。

于 2012-07-27T21:49:45.713 に答える
1

この答えは2つのことを前提としています。

  1. バイナリブロブをしっかりと(穴なしで)パックする必要があります。
  2. データメンバーに整列されていない方法でアクセスすることは望ましくありません(これは、コンパイラーがデフォルトで必要とする方法で整列されているデータメンバーにアクセスする場合に比べて低速です)。

この場合、大きな「blob」をバイト指向のストリームとして扱う設計を検討する必要があります。このストリームでは、自然に配置されたオブジェクトにデータを入力するタグ/値のペアをマーシャル/デマーシャルします。

このスキームを使用すると、両方の長所を活用できます。密集したblobを取得しますが、blobからオブジェクトを抽出すると、自然に配置されるため、オブジェクトメンバーへのアクセスが高速になります。また、移植性があり1、コンパイラ拡張機能に依存しません。欠点は、ブロブに入れることができるすべてのタイプに対して記述する必要のある定型コードです。

初歩的な例:

#include <cassert>
#include <iomanip>
#include <iostream>
#include <stdint.h>
#include <vector>

enum BlobKey
{
    kBlobKey_Widget,
    kBlobKey_Gadget
};

class Blob
{
public:
    Blob() : cursor_(0) {}

    // Extract a value from the blob. The key associated with this value should
    // already have been extracted.
    template <typename T>
    Blob& operator>>(T& value)
    {
        assert(cursor_ < bytes_.size());
        char* dest = reinterpret_cast<char*>(&value);
        for (size_t i=0; i<sizeof(T); ++i)
            dest[i] = bytes_[cursor_++];
        return *this;
    }

    // Insert a value into the blob
    template <typename T>
    Blob& operator<<(const T& value)
    {
        const char* src = reinterpret_cast<const char*>(&value);
        for (size_t i=0; i<sizeof(T); ++i)
            bytes_.push_back(src[i]);
        return *this;
    }

    // Overloads of << and >> for std::string might be useful

    bool atEnd() const {return cursor_ >= bytes_.size();}

    void rewind() {cursor_ = 0;}

    void clear() {bytes_.clear(); rewind();}

    void print() const
    {
        using namespace std;
        for (size_t i=0; i<bytes_.size(); ++i)
            cout << setfill('0') << setw(2) << hex << int(bytes_[i]) << " ";
        std::cout << "\n" << dec << bytes_.size() << " bytes\n";
    }

private:
    std::vector<uint8_t> bytes_;
    size_t cursor_;
};

class Widget
{
public:
    explicit Widget(int a=0, short b=0, char c=0) : a_(a), b_(b), c_(c) {}
    void print() const
    {
        std::cout << "Widget: a_=" << a_ << " b=" << b_
                  << " c_=" << c_ << "\n";
    }
private:
    int a_;
    short b_;
    long c_;
    friend Blob& operator>>(Blob& blob, Widget& widget)
    {
        // Demarshall members from blob
        blob >> widget.a_;
        blob >> widget.b_;
        blob >> widget.c_;
        return blob;
    };
    friend Blob& operator<<(Blob& blob, Widget& widget)
    {
        // Marshall members to blob
        blob << kBlobKey_Widget;
        blob << widget.a_;
        blob << widget.b_;
        blob << widget.c_;
        return blob;
    };
};

class Gadget
{
public:
    explicit Gadget(long a=0, char b=0, short c=0) : a_(a), b_(b), c_(c) {}
    void print() const
    {
        std::cout << "Gadget: a_=" << a_ << " b=" << b_
                  << " c_=" << c_ << "\n";
    }
private:
    long a_;
    int b_;
    short c_;
    friend Blob& operator>>(Blob& blob, Gadget& gadget)
    {
        // Demarshall members from blob
        blob >> gadget.a_;
        blob >> gadget.b_;
        blob >> gadget.c_;
        return blob;
    };
    friend Blob& operator<<(Blob& blob, Gadget& gadget)
    {
        // Marshall members to blob
        blob << kBlobKey_Gadget;
        blob << gadget.a_;
        blob << gadget.b_;
        blob << gadget.c_;
        return blob;
    };
};

int main()
{
    Widget w1(1,2,3), w2(4,5,6);
    Gadget g1(7,8,9), g2(10,11,12);

    // Fill blob with widgets and gadgets
    Blob blob;
    blob << w1 << g1 << w2 << g2;
    blob.print();

    // Retrieve widgets and gadgets from blob
    BlobKey key;
    while (!blob.atEnd())
    {
        blob >> key;
        switch (key)
        {
            case kBlobKey_Widget:
                {
                    Widget w;
                    blob >> w;
                    w.print();
                }
                break;

            case kBlobKey_Gadget:
                {
                    Gadget g;
                    blob >> g;
                    g.print();
                }
                break;

            default:
                std::cout << "Unknown object type in blob\n";
                assert(false);
        }
    }
}

Boostを使用できる場合は、この回答のように、バイナリメモリストリームでBoost.Serializationを使用することをお勧めします。


(1)ポータブルとは、ソースコードをどこでもコンパイルできることを意味します。結果のバイナリブロブは、エンディアンと整数サイズが異なる他のマシンに転送された場合、移植できなくなります。

于 2012-07-27T23:16:23.653 に答える
0

@Negaiは、観察されたサイズを取得する理由を説明しました。

また、「密集した」データに関する仮定を再検討する必要があります。上記の構造で、構造に穴があります。32ビットのintと16ビットのshortを想定すると、shortの後に2バイトの穴があり、charの後に3バイトの穴があります。しかし、このスペースは構造物の中にあるので、それは問題ではありません。

言い換えると、密集したデータ構造を取得するか、整列されたデータ構造を取得しますが、両方を取得することはできません。

通常、コンパイラがデフォルトで実行する「整列された」動作を取得するために特別なことを行う必要はありません。#pragma packは、データを整列させるのではなく「パック」する場合に役立ちます。つまり、データを整列させるためにコンパイラーによって導入されたいくつかの穴を削除します。

于 2012-07-27T22:08:34.927 に答える
0

これを試しましたか?

class A {
public:
    union {
        uint64_t dummy;

        int data;
    };
};

Aとそのメンバーのインスタンスは、data常に8バイトに整列されます。もちろん、これは前に4バイトのデータ型を絞り込んだ場合は無意味です。これも8バイトである必要があります。

于 2012-07-28T01:09:05.567 に答える