2
struct Point
{
    double X;
    double Y;
};

Q1) 以下の移植可能な (コンパイラ/マシン)

Point point = { 1.1, 2.2 };
double arr[2] = {};
memcpy(arr, point, sizeof(double)*2);

Q2) 構造体の配列も同様

Point *pPoints = new Point[numPoints];
double *pArr = new double[2*numPoints];
memcpy(pArr, pPoints, sizeof(double)*2*numPoints);

Windows/MSVC では、両方が成功することを期待しています。

編集:すべての可能な構造体/クラスに対してこれらの質問をしているわけではありません。構造体「ポイント」のこの特定のケースを求めています(注意:ポッドは2つだけで、仮想メンバー/ユーザーコンストラクター/ユーザーデストラクターはありません)。これは、コンパイラ間の構造体のアライメントとメモリ レイアウトに関係する C の質問かもしれません。

これまでのところ、c/c++ 標準では Point のレイアウトについて何も強制されていないことがわかったので、静的アサートで自分で確認する必要があります。正しいですか?

4

4 に答える 4

8

あなたのコードは、sizeof(struct Point) == 2*sizeof(double);. これは危険な仮定です。なぜなら、コードを書いてテストするときには正しいからです。ただし、定義ではなく運によって正しいのです。運は尽きる癖があります:)

ほとんどの場合、この場合、問題が発生することはありません ( の定義がstruct Point変更される可能性はほとんどなく、マシンのアライメントの問題もこのタイプの移植性にある可能性が低いためです)。そうは言っても、コードのベースにするのは恐ろしいパターンです。

于 2013-07-01T10:37:00.290 に答える
0

さて、@mahが言ったことを完全に支持するという事実から始めましょう。確かにそれはひどいことであり、可能であれば避けるべきです。

しかし、それが不可能な場合もあります。たとえば、まったく逆のことを行う必要がある場合があります。特定の順序で並べられた数値のストリームを受け取り、それを構造体に「アンパック」して、より適切に処理したい場合です。そこでは、メモリ レイアウトを厳密に制御する必要があります。

そのような場合、struct Point適切なパッキング ディレクティブで を装飾する場合、コンパイラにalign を追加しないよう#pragma pack(1)指示する場合があります。

これは #pragma であることに注意してください。一部はやや普遍的に見えるかもしれませんが、定義上、コンパイラ/プラットフォーム固有のものです。コンパイラを変更したり、プラグマの扱いが異なるバージョンにアップグレードした場合に備えて、sizeofs が本当に等しいかどうかを確認する簡単なアサーションをいくつか追加してください。

コンパイラが pack(1) プラグマ (または類似のもの) を理解していると仮定すると、コードは安全になり、そのような POD 構造体のサイズは実際に 2*double に等しくなります。ここで良い例を参照してください https://stackoverflow.com/a/3318475/717732

実際、配列のパッキングについては覚えていません。配列がゼロアラインでパックされることが保証されていることはほぼ確実です。しかし、ほぼ確実です。STDをチェックするのが最善です。

于 2013-07-01T10:50:08.283 に答える
0

理論的には、構造体はメンバー間および末尾の後にパディングを持つことができます。そのため、必ずしもプレーンな double とのレイアウト互換性があるとは限りません。しかし、 sizeof(Point) == 2* sizeof(double) を確保するために 0 パッキングと static_assert を追加すると、実際に失敗する方法はわかりません。

于 2013-07-01T10:38:21.733 に答える