2012-06-21 14 views
6

C構造体のサイズを16バイト(16B/32B/48B/..)の倍数にします。 どのサイズになるかは関係ありませんが、16Bの倍数である必要があります。 これを行うにはどのようにコンパイラを強制できますか?おかげさまで C構造体のサイズの整列

+4

コンパイラとは何ですか? – Joe

+1

あなたのタイトルは単語の整列を使用しますが、質問の本文は構造体のサイズについて語ります。あなたは実際に何を達成したいのですか?そして、なぜ私はまた興味があります。 –

+0

ここでは、ユニオンを使用して特定のサイズにパッドするソリューションを提供する既存の記事です。しかし、その解決策は構造体[Size of Struct](http://stackoverflow.com/questions/8705665/force-specific-struct-size-in-c)のサイズを知る必要がありますが、あなたがする必要があるのは、数値定数ではなく、(sizeof(struct it)/ 16 + 1)* 16のようなchar配列のサイズ計算。 –

答えて

5

C構造体のサイズは、構造体のメンバー、型、およびその数によって異なります。実際には、構造体をいくつかのサイズの倍数にするようコンパイラーに強制する標準的な方法はありません。コンパイラの中にはプラグマが用意されているものもありますが、これは実際には異なるものですが、境界の境界を設定することができます。そのような設定をしたり、そのようなプラグマを提供するものがあるかもしれません。

しかし、この1つの方法は、構造体のメモリ割り当てを行い、メモリ割り当てを強制して次の16バイトサイズにすることです。

このような構造体があれば、

struct _simpleStruct { 
    int iValueA; 
    int iValueB; 
}; 

次に、次のようなことができます。

{ 
    struct _simpleStruct *pStruct = 0; 
    pStruct = malloc ((sizeof(*pStruct)/16 + 1)*16); 
    // use the pStruct for whatever 
    free(pStruct); 
} 

これは、あなたが懸念していた限り、サイズを次の16バイトサイズにプッシュすることです。しかし、メモリアロケータは実際にはそのサイズのブロックを与えるかもしれないし、そうでないかもしれません。メモリのブロックは、実際にあなたの要求よりも大きいかもしれません。

このような特別な処理を行う場合、たとえば、この構造体をファイルに書き込む場合、ブロックサイズを知りたい場合は、同じ構造体で使用されているのと同じ計算を行う必要があります。 sizeof()演算子を使用して構造体のサイズを計算するのではなく、malloc()を使用します。

したがって、次のようなマクロを使用して独自のsizeof()演算子を記述します。

#define SIZEOF16(x) ((sizeof(x)/16 + 1) * 16) 

私が知る限り、割り当てられたブロックのサイズをポインタから引き出すための信頼できる方法はありません。通常、ポインタには、割り当てられたブロックサイズなどのさまざまなメモリ管理情報を含むメモリヒープ管理関数によって使用されるメモリ割り当てブロックがあります。このサイズは、実際には要求されたメモリ量よりも大きい場合があります。ただし、このブロックのフォーマットと、実際のメモリアドレスとの相対的な位置は、Cコンパイラの実行時間によって異なります。

+0

あなたは[malloc()の戻り値をCでキャストしてはいけません(http://stackoverflow.com/a/605858/28169)。 – unwind

5

これは、ISO C標準の深い位置合わせが指定されていないため(コンパイラーにはアライメントが起こるかもしれないが、実装方法については詳しくは述べられていない)、アライメントが指定されていないため、

コンパイラのツールチェーンには、実装固有のものを調べる必要があります。構造定義に追加できる#pragma pack(またはalignまたはその他のもの)を提供することがあります。

これは言語拡張機能として提供される場合もあります。例えば、GCCは、あなたは、アライメントを制御しそのうちの一つの定義に属性を追加することができます:

struct mystruct { int val[7]; } __attribute__ ((aligned (16))); 
11

のMicrosoft Visual C++の場合:GCCの場合

#pragma pack(push, 16) 

struct _some_struct 
{ 
    ... 
} 

#pragma pack(pop) 

struct _some_struct { ... } __attribute__ ((aligned (16))); 

例:

#include <stdio.h> 

struct test_t { 
    int x; 
    int y; 
} __attribute__((aligned(16))); 

int main() 
{ 
    printf("%lu\n", sizeof(struct test_t)); 
    return 0; 
} 

gcc -o main main.cと入力すると、16が出力されます。他のコンパイラも同様です。

+1

gcc __attribute__が整列している場合、実際に構造体のサイズを16Bの倍数に強制していますか?それとも、構造体の開始アドレスが16Bに揃っていることを保証するだけですか? –

+1

構造の開始アドレスとサイズの両方が16Bに揃えられます。これは、構造体の配列の要素の正しい位置合わせを保証するために行われます。 – Romeo

+0

これは当てはまりません。 __attribute(aligned(x)))マクロは、構造体をxバイト境界に割り当て、構造体のサイズとは何も関係ありません。 http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc /Variable-Attributes.html –

3

あなたはおそらくパディングを追加することができます秒1であなたの実際の構造体を包む、二重の構造体を行うことができます:

struct payload { 
    int a; /*Your actual fields. */ 
    float b; 
    char c; 
    double d; 
}; 

struct payload_padded { 
    struct payload p; 
    char padding[16 * ((sizeof (struct payload) + 15)/16)]; 
}; 

次に、あなたがパディング構造体を操作できます。もちろん

struct payload_padded a; 

a.p.d = 43.3; 

構造の最初のメンバーが構造体の開始位置から0バイトを開始し、ポインタがstruct payloadへのポインタであるかのようにstruct payload_paddedを扱うことを利用できます。

float d_plus_2(const struct payload *p) 
{ 
    return p->d + 2; 
} 

/* ... */ 

struct payload_padded b; 
const double dp2 = d_plus_2((struct payload *) &b);