4

プロジェクトでいくつかのサードパーティ コードを継承しました。ヘッダー ファイルとソースのないバイナリ ライブラリで構成されているため、別の設定で再コンパイルすることはできません。

ヘッダーは、コンパイル時のアサートのようなトリック (typedef式が失敗した場合は負のサイズの配列を使用する) を使用して、適切な構造体の配置を保証しますが、32 ビット モードでは機能しないようです。

問題全体をキャプチャするスタンドアロンの小さなプログラムを次に示します。

#include <stdio.h>
#include <stddef.h>

#pragma pack(push, 8)
struct test {char _; long long a;};
typedef char pack_test[(offsetof(test, a) == 8) ? 1 : -1];
#pragma pack(pop)

int main(int argc, char *argv[])
{
        printf("%d\n", offsetof(test, a));
        return 0;
}

上記のコードは、clang 3.0 と、すぐに手に入れることができる最近の gcc バージョン (4.5 から 4.7) の両方でコンパイルに失敗します。パッキング プラグマはまったく効果がありません。コンパイラはメンバーaを 4 バイトに揃え続けます (コメントアウトすることで確認できますtypedef)。

何故ですか?このアサーションが失敗しないようにコードを修正し、ABI との互換性を維持しながら、ヘッダー内のすべての構造体を調べて末尾にattributes を追加する必要がないようにするにはどうすればよいですか?

4

1 に答える 1

4

32 ビット システムでは、along longは 8 バイトのアラインメントを必要としない場合があり、4 バイトで十分なはずです。結局のところ、最初のワードが 8 バイトでアラインされているか 4 バイトでアラインされているかに関係なく、メモリから 2 つのワード全体をフェッチすることになります。

属性で 8 バイト アラインメントを強制することができます

struct test { char _; long long a __attribute__ ((aligned(8))); };

(おそらく間違っています、私はgccの属性に精通していません)

もちろん、ダミー メンバーを に追加してstruct、目的の配置を確保することもできます。

struct test { char _; char dummy[7]; long long a; }

それは実際にはうまくいくはずです。

于 2013-01-14T17:11:26.123 に答える