次のような構造定義が与えられます
struct foo {
int a, b, c;
};
32ビットビルドであっても、常に64ビットアドレスにアラインする必要があることを指定するための最良の(最も単純で、最も信頼性が高く、移植性のある)方法は何ですか?私はGCC4.5.2でC++11を使用しており、Clangもサポートしたいと思っています。
GCCを使用していて、Clangをサポートすることを望んでいると言うので、GCCのaligned
属性でうまくいくはずです。
struct foo {
int a, b, c;
} __attribute__((__aligned__(8))); // aligned to 8-byte (64-bit) boundary
以下は、すべてではありませんが、多くの異なる実装で機能するという意味で、適度に移植可能です。
union foo {
struct {int a, b, c; } data;
double padding1;
long long padding2;
};
static char assert_foo_size[sizeof(foo) % 8 == 0 ? 1 : -1];
次のいずれかを行わない限り、コンパイルに失敗します。
foo
た。これは通常、アライメント要件の理由でのみ発生します。foo.data
が非常に奇妙である、またはlong long
、double
3 intより大きく、8の倍数です。これは、必ずしも8整列であることを意味するわけではありません。ただし、サポートする必要があるコンパイラは2つだけであり、clangは設計上かなりgcc互換であるため、__attribute__
動作するコンパイラを使用してください。テストしていないコンパイラで(うまくいけば)動作するコードを今すぐ書きたい場合にのみ、他のことを行うことを考えてください。
C ++ 11はalignof
、サイズをテストする代わりにテストできるを追加します。誤検知は削除されますが、それでも、ユニオンが必要な配置を作成できず、したがってコンパイルに失敗する、いくつかの準拠した実装が残ります。また、私のsizeof
トリックは非常に限られています。構造に3つではなく4つのintがある場合はまったく役に立ちませんが、同じことがalignof
あります。gccとclangがサポートしているバージョンがわからないalignof
ため、最初はそれを使用しませんでした。難しいとは思わなかったでしょう。
ちなみに、のインスタンスfoo
が動的に割り当てられると、物事は簡単になります。まず、glibcまたは同様malloc
の実装はとにかく8整列するのではないかmalloc
と思います。8バイト整列の基本タイプがある場合は、そうする必要があります。glibcmalloc
は、存在するかどうかを心配するのではなく、常に実行すると思います。与えられたプラットフォーム。第二に、posix_memalign
確かなことがあります。
を使用する必要があります__attribute__((aligned(8))
。ただし、この説明では、割り当てられた構造のサイズが8バイトの倍数であることを確認するだけであることがわかりました。開始アドレスが複数であることを確認するものではありません。
例えば。私が使用している場合__attribute__((aligned(64))
、mallocは開始アドレスが0xed2030である64バイト長の構造体を返す可能性があります。
開始アドレスを整列させたい場合は、aligned_alloc:gccalignedallocationを使用する必要があり
ます。aligned_alloc(64, sizeof(foo)
0xed2040を返します。
ポータブル?私は本当にポータブルな方法について本当に知りません。GCCにはが__attribute__((aligned(8)))
あり、他のコンパイラにも同等のものがある場合があります。これは、プリプロセッサディレクティブを使用して検出できます。
gcc 4.5.2は十分に古く、標準バージョンをまだサポートしていないと確信していますが、C ++ 11では、特にアライメントを処理するためにいくつかのタイプが追加されていますstd::aligned_storage
(std::aligned_union
詳細については§20.9.7.6を参照してください)。詳細)。
これを行う最も明白な方法は、Boostの実装aligned_storage
(または、TR1がある場合はTR1)を使用することだと私には思えます。それを望まない場合でも、ほとんどのコードで標準バージョンを使用することについては一生懸命考えており、標準を実装するコンパイラに更新するまで、自分で使用するために標準バージョンの小さな実装を作成するだけです。__declspec(align...
ただし、ポータブルコードは、または__attribute__(__aligned__, ...
直接のようなものを使用するほとんどのコードとは少し異なります。
特に、要求されたアラインメントを持つ要求されたサイズのrawバッファーを提供するだけです。その場合、新しい配置のようなものを使用して、そのストレージに同じタイプのオブジェクトを作成するのはあなた次第です。
その価値については、gccのディレクティブにaligned_storage
基づくの実装を簡単に説明します。__attribute__(__aligned__,...
template <std::size_t Len, std::size_t Alignment>
struct aligned_storage {
typedef struct {
__attribute__(__aligned__(Alignment)) unsigned char __data[Len];
} type;
};
これを使用する方法を示すための簡単なテストプログラム:
struct foo {
int a, b, c;
void *operator new(size_t, void *in) { return in; }
};
int main() {
stdx::aligned_storage<sizeof(foo), 8>::type buf;
foo& f = *new (static_cast<void*>(&buf)) foo();
int address = *reinterpret_cast<int *>(&f);
if (address & 0x3 != 0)
std::cout << "Failed.\n";
f.~foo();
return 0;
}
もちろん、実際の使用では、ここで示した醜さのほとんどをまとめて非表示にします。このままにしておくと、(理論的/将来の)携帯性の価格はおそらく高すぎるでしょう。
[[gnu::aligned(64)]] in c++11 annotation
std::atomic <int64_t> ob [[gnu::aligned(64)]]