29

私は次の構造を持っています

typedef struct _person {
    int age;
    char sex;
    char name[];
}person;

を使用せずにインスタンスを作成し、柔軟な配列メンバーで構造を初期化する方法について、いくつかの基本的なインターネット検索を行いました (ただし失敗しました) malloc()

例:次のような通常の構造の場合

struct a {
    int age; 
    int sex;
};

のインスタンスを作成し、次のstruct aように初期化できます

struct a p1 = {10, 'm'};

しかし、(上記のように) 柔軟な配列を含む構造体_personの場合、どのようにインスタンスを作成し、通常のように初期化できますstructuresか?

それは可能ですか?もしそうなら、初期化中に配列サイズと初期化される実際の値をどのように渡すのでしょうか?

(また)

柔軟な配列を持つ構造体を作成する唯一の方法はmalloc()、C99 仕様で言及されているように使用することであるというのは本当6.7.2.1 Structure and union specifiers - point #17ですか?!

4

3 に答える 3

12

いいえ、柔軟なアレイは常に手動で割り当てる必要があります。ただし、使用callocしてフレキシブル部分を初期化し、複合リテラルを使用して固定部分を初期化することができます。inlineこれを次のような割り当て関数でラップします。

typedef struct person {
  unsigned age;
  char sex;
  size_t size;
  char name[];
} person;

inline
person* alloc_person(int a, char s, size_t n) {
  person * ret = calloc(sizeof(person) + n, 1);
  if (ret) memcpy(ret,
                  &(person const){ .age = a, .sex = s, .size = n},
                  sizeof(person));
  return ret;
}

これにより、割り当てが呼び出し元に成功したかどうかのチェックが終了することに注意してください。

sizeここに含めたようにフィールドが必要ない場合は、マクロで十分です。callocを実行する前にの戻りを確認することは不可能であるということだけですmemcpy。これまでにプログラムしたすべてのシステムでは、これは比較的うまく中止されます。一般的に、返品mallocはそれほど重要ではないと思いますが、その件に関しては意見が大きく異なります。

これはおそらく(その特別な場合に)オプティマイザーにコードを周囲に統合するためのより多くの機会を与える可能性があります:

#define ALLOC_PERSON(A,  S,  N)                                 \
((person*)memcpy(calloc(sizeof(person) + (N), 1),               \
                 &(person const){ .age = (A), .sex = (S) },     \
                 sizeof(person)))

編集:これが関数よりも優れている可能性があるのは、コンパイル時定数Aである場合です。Sその場合、複合リテラルはconst修飾されているため、静的に割り当てることができ、その初期化はコンパイル時に実行できます。さらに、同じ値を持つ複数の割り当てがコードに表示される場合、コンパイラはその複合リテラルの単一のコピーのみを実現できます。

于 2011-12-31T13:13:50.950 に答える
7

使用できるいくつかのトリックがあります。それはあなたの特定のアプリケーションに依存します。

単一の変数を初期化する場合は、正しいサイズの構造体を定義できます。

   struct  {
        int age;
        char sex;
        char name[sizeof("THE_NAME")];
    } your_variable = { 55, 'M', "THE_NAME" };

問題は、変数を "person" として解釈するためにポインター キャストを使用する必要があることです (例: "*(person *)(&your_variable)")。しかし、これを回避するために包含ユニオンを使用できます。

union {
 struct { ..., char name[sizeof("THE_NAME")]; } x;
 person p;
} your_var = { 55, 'M', "THE_NAME" };

したがって、your_var.p のタイプは「person」です。マクロを使用して初期化子を定義することもできるため、文字列を一度だけ書き込むことができます。

#define INIVAR(x_, age_, sex_ ,s_) \
   union {\
     struct { ..., char name[sizeof(s_)]; } x;\
     person p;\
    } x_ = { (age_), (sex_), (s_) }

INIVAR(your_var, 55, 'M', "THE NAME");

もう 1 つの問題は、このトリックが「人」の配列を作成するのに適していないことです。配列の問題は、すべての要素が同じサイズでなければならないことです。この場合、 a のconst char *代わりに aを使用する方が安全char[]です。または動的割り当てを使用してください;)

于 2011-12-31T16:30:20.527 に答える
4

柔軟な配列メンバーを持つ構造体型は、柔軟な配列メンバーが省略されたかのように扱うことができるため、このように構造体を初期化できます。

person p = { 10, 'x' };

ただし、割り当てられた柔軟な配列のメンバーはなく、柔軟な配列のメンバーにアクセスしようとしたり、その末尾を超えたメンバーへのポインターを形成しようとしたりする試みは無効です。この配列に実際に要素を持つ柔軟な配列メンバーを持つ構造体のインスタンスを作成する唯一の方法は、たとえば を使用して動的にメモリを割り当てることmallocです。

于 2011-12-31T10:55:09.477 に答える