11

以下に示す同様のデモとして実装された1つのコードを見つけました。

struct st
{
 int a;
 struct
 {
 int b;
 };
};

6.58struct/union内の名前のないフィールドstructs/unions

によって許可されているようにISO C11

しかし、それの利点は何ですか?

とにかく私は同じ方法でデータメンバーにアクセスできるので

int main()
{
 struct st s;
 s.a=11;
 s.b=22;
 return 0;
}

gcc 4.5.2でコンパイルされ、、

gcc -Wall demo.c -o demo 

エラーなし、

4

4 に答える 4

16

構造体内の匿名の構造体である必要はありませんが、これはあまり便利ではありません。これは通常、パディングを追加することでレイアウトをわずかに変更するだけで、他の目に見える効果はありません(子構造体のメンバーをインライン化する場合と比較して)親構造体)。

匿名の構造体/共用体の利点は他にもあると思います。それらを使用して、匿名の構造体を共用体内に配置したり、匿名の共用体を構造体内に配置したりできます。

例:

union u
{
  int i;
  struct { char b1; char b2; char b3; char b4; };
};
于 2012-11-14T10:29:20.387 に答える
14

メリットは明らかですよね?プログラマーが名前を思い付くのを防ぎます!名前を付けるのは難しいので、本当に必要がなければそうしないようにできるのはいいことです。

また、これstructはローカルであり、他の場所では使用されないことを示す非常に明確なシグナルですが、親構造体のフィールドであるというコンテキストでは、不必要な結合の可能性を減らすため、非常に優れた情報です。

staticそれを;と考えてください。これは、グローバルシンボルの可視性をそれらが表示されるコンパイル単位に制限structする方法と同様の方法で(もちろん、同等ではありませんが)、内側の可視性を外側のシンボルに制限します。static

于 2012-11-14T09:55:42.067 に答える
4

匿名の大きなメリットに出くわしunionました。ただし、これは気弱な人のための話ではなく、推奨される方法でもないことに注意してください。

注:c99にない構造体内の匿名共用体も参照してください。

何百ものソースコードファイルの古いCプログラムには、メンバーとしてstructを含むグローバル変数aがあります。structしたがって、グローバル変数の型定義は次のようになります。

typedef struct {
    LONG       lAmount;
    STRUCTONE  largeStruct;  // memory area actually used for several different struct objects
    ULONG      ulFlags;
} STRUCTCOMMON;

structSTRUCTONEは、いくつかの大きな構造体の1つでしたが、このコードが記述された時点では、他の構造体はすべてSTRUCTONEよりも小さかったです。したがって、このメモリ領域は、largeStructとして使用されていましたunionが、そのことを示す適切なソースステートメントがありませんでした。代わりstructに、を使用してさまざまな変数がこの領域にコピーされましたmemcpy()。さらに悪いことに、これはグローバル変数の実際の名前による場合もあれば、グローバル変数へのポインターによる場合もあります。

時間の経過とともに通常発生するように、最近の変更により、他の構造体の1つが最大になりました。そして、さまざまなエイリアスやその他すべてのファイルとともに、これがどこで使用されているかを探すために、100個のファイルを調べる必要がありました。

そして、匿名の組合を思い出しました。そこでtypedef、を次のように変更しました。

typedef struct {
    LONG       lAmount;
    union {
        // anonymous union to allow for allocation of largest space needed
        STRUCTONE  largeStruct;  // memory area actually used for several different struct objects
        STRUCTTHREE  largerStruct;  // memory area for even larger struct
     };
    ULONG      ulFlags;
} STRUCTCOMMON;

そして、すべてを再コンパイルしました。

そのため、ソースコードレビューと回帰テストのすべての日が、不幸にも私が待ち望んでいたものはもはや必要ありません。

そして、このグローバルを使用してソースをゆっくりと変更するプロセスを開始して、このソースを自分のタイムテーブルでより最新の標準に引き上げることができます。

補遺-匿名struct内で匿名union

この同じソースコード本体で作業しているときに、同じ長さであると想定されていたいくつかの異なる構造体の1つからの日付を含む可能性のあるバイナリレコードを使用して、この手法のアプリケーションに遭遇しました。私が見つけた問題は、プログラマーのエラーが原因でした。1つの構造体が他の構造体とはサイズが異なっていました。

この問題を修正する一環として、コンパイラがデータ構造の正しいサイズを把握できるようにするソリューションが必要でした。

これらの構造体には、すべて同じサイズにするためにパディング変数が追加された構造体のいくつかのメンバーにいくつかの違いが含まれていたため、構造体の1つを除いて正常に機能する匿名の共用体を使用しました。

ユニオンの一部として匿名構造体を追加できることがわかりました。これにより、ユニオンのさまざまなメンバーと追加された匿名構造体の名前が異なる限り、VisualStudio2015で正常にコンパイルされます。

重要な注意:このソリューションでは#pragma pack(1)、Visual Studio 2015で、バイト境界に構造体と共用体をパックする必要があります。コンパイラを使用しないpragmaと、さまざまな構造体や共用体に不明なパディングが導入される可能性があります。

匿名と匿名defineを標準化するために以下を作成しました。unionstruct

#define PROGRPT_UNION_STRUCT  \
    union {  \
        SHORT   sOperand1;                              /* operand 1 (SHORT) */  \
        LONG    lOperand1;                              /* operand 1 (LONG) */  \
        PROGRPT_ITEM Operand1;                          /* operand 1 */  \
        struct {  \
            UCHAR   uchReserved3;                           /* */  \
            USHORT  usLoopEnd;                              /* offset for loop end */  \
            UCHAR   uchReserved4;                           /* */  \
        };  \
    };

次に、ファイルから読み取られたデータレコード内のバイナリデータにアクセスするために使用されるいくつかの構造体のうちの3つのサンプルのようにそれを使用しました。

    /* loop record */
typedef struct {
    UCHAR   uchOperation;                           /* operation code (LOOP) */
    UCHAR   uchRow;                                 /* position (row) */
    UCHAR   uchLoopBrace;                           /* loop brace (begin/end) */
    UCHAR   uchReserved1;                           /* */
    TCHAR   auchReserved2[ 2 ];                     /* */
    UCHAR   uchCondition;                           /* condition code */
    PROGRPT_ITEM LoopItem;                          /* loop record */
    PROGRPT_UNION_STRUCT
    PROGRPT_ITEM Reserved5;                         /* */
} PROGRPT_LOOPREC;

    /* print record */
typedef struct {
    UCHAR   uchOperation;                           /* operation code (PRINT) */
    UCHAR   uchRow;                                 /* position (row) */
    UCHAR   uchColumn;                              /* position (column) */
    UCHAR   uchMaxColumn;                           /* max no of column */
    TCHAR   auchFormat[ 2 ];                        /* print format/style */
    UCHAR   uchCondition;                           /* condition code */
    PROGRPT_ITEM PrintItem;                         /* print item */
    PROGRPT_UNION_STRUCT
    PROGRPT_ITEM Operand2;                          /* ope2 for condition */
} PROGRPT_PRINTREC;

    /* mathematics record ( accumulator.total = LONG (+,-,*,/) opr2) */
typedef struct {
    UCHAR   uchOperation;                           /* operation code (MATH) */
    UCHAR   uchRow;                                 /* position (row) */
    UCHAR   uchColumn;                              /* position (column) */
    UCHAR   uchMaxColumn;                           /* max no of column */
    TCHAR   auchFormat[ 2 ];                        /* format style */
    UCHAR   uchCondition;                           /* condition code */
    PROGRPT_ITEM Accumulator;                       /* accumulator */
    PROGRPT_UNION_STRUCT
    PROGRPT_ITEM Operand2;                          /* operand 2 */
} PROGRPT_MATHTTL;

もともとは

typedef struct {
    UCHAR   uchOperation;                           /* operation code (LOOP) */
    UCHAR   uchRow;                                 /* position (row) */
    UCHAR   uchLoopBrace;                           /* loop brace (begin/end) */
    UCHAR   uchReserved1;                           /* */
    TCHAR   auchReserved2[ 2 ];                     /* */
    UCHAR   uchCondition;                           /* condition code */
    PROGRPT_ITEM LoopItem;                          /* loop record */
    UCHAR   uchReserved3;                           /* */
    USHORT  usLoopEnd;                              /* offset for loop end */
    UCHAR   uchReserved4;                           /* */
    PROGRPT_ITEM Reserved5;                         /* */
} PROGRPT_LOOPREC;

    /* print record */
typedef struct {
    UCHAR   uchOperation;                           /* operation code (PRINT) */
    UCHAR   uchRow;                                 /* position (row) */
    UCHAR   uchColumn;                              /* position (column) */
    UCHAR   uchMaxColumn;                           /* max no of column */
    TCHAR   auchFormat[ 2 ];                        /* print format/style */
    UCHAR   uchCondition;                           /* condition code */
    PROGRPT_ITEM PrintItem;                         /* print item */
    PROGRPT_ITEM Operand1;                          /* ope1 for condition */
    PROGRPT_ITEM Operand2;                          /* ope2 for condition */
} PROGRPT_PRINTREC;

    /* mathematics record ( accumulator.total = LONG (+,-,*,/) opr2) */
typedef struct {
    UCHAR   uchOperation;                           /* operation code (MATH) */
    UCHAR   uchRow;                                 /* position (row) */
    UCHAR   uchColumn;                              /* position (column) */
    UCHAR   uchMaxColumn;                           /* max no of column */
    TCHAR   auchFormat[ 2 ];                        /* format style */
    UCHAR   uchCondition;                           /* condition code */
    PROGRPT_ITEM Accumulator;                       /* accumulator */
    LONG    lOperand1;                              /* operand 1 (LONG) */
    PROGRPT_ITEM Operand2;                          /* operand 2 */
} PROGRPT_MATHTTL;

union次のようなすべてのさまざまなレコードタイプのを使用します。

typedef union {
    PROGRPT_LOOPREC  Loop;                          /* loop record */
    PROGRPT_PRINTREC Print;                         /* print record */
    PROGRPT_MATHOPE  MathOpe;                       /* math (with operand) */
    PROGRPT_MATHTTL  MathTtl;                       /* math (with total) */
    PROGRPT_MATHCO   MathCo;                        /* math (with count) */
} PROGRPT_RECORD;

これらのレコード形式は、次のようなコードで使用されます。

for ( usLoopIndex = 0; usLoopIndex < usMaxNoOfRec; ) {
    ULONG            ulActualRead = 0;       /* actual length of read record function */
    PROGRPT_RECORD   auchRecord;

    /* --- retrieve a formatted record --- */
    ProgRpt_ReadFile( ulReadOffset, &auchRecord, PROGRPT_MAX_REC_LEN, &ulActualRead );
    if ( ulActualRead != PROGRPT_MAX_REC_LEN ) {
        return ( LDT_ERR_ADR );
    }

    /* --- analyze operation code of format record, and
        store it to current row item buffer --- */
    switch ( auchRecord.Loop.uchOperation ) {
    case PROGRPT_OP_PRINT:  /* print operation */
        sRetCode = ProgRpt_FinPRINT( &ReportInfo, &auchRecord.Print, uchMinorClass, NULL );
        break;

    case PROGRPT_OP_MATH:   /* mathematics operation */
        sRetCode = ProgRpt_FinMATH(&auchRecord.MathOpe, NULL );
        break;

    case PROGRPT_OP_LOOP:   /* loop (begin) operation */
        ProgRpt_PrintLoopBegin( &ReportInfo, &auchRecord.Loop );

        switch ( auchRecord.Loop.LoopItem.uchMajor ) {
        case PROGRPT_INDKEY_TERMNO:
            sRetCode = ProgRpt_IndLOOP( &ReportInfo, &auchRecord.Loop, uchMinorClass, usTerminalNo, ulReadOffset );
            usLoopIndex  += auchRecord.Loop.usLoopEnd;
            ulReadOffset += ( PROGRPT_MAX_REC_LEN * auchRecord.Loop.usLoopEnd );
            break;

        default:
            return ( LDT_ERR_ADR );
        }
        break;

    default:
        return ( LDT_ERR_ADR );
    }

    //    .......
于 2016-02-18T23:49:24.170 に答える
0

ポインタを介してアクセスする連続したアドレス構造を開発する際に、匿名構造体を使用しました。具体的には、親構造体内で匿名構造体を使用して、ラベル付けされたデータの小さな部分に分割されるメモリの特定の部分をビットフィールド化できるようにします。

コンパイラがビットフィールド情報をパックする方法に注意してください。ビットフィールド構造体の最初のメンバーは、LSBまたはMSBのいずれかです。

typedef struct
{
uint32_t a;
    
    struct 
    {
        uint32_t b : 16;
        uint32_t c : 8;
        uint32_t d : 7;
        uint32_t e : 1;
    };
}Parent;

#define ADDRESS ((Parent*)(uint16_t)0xF0F0) 

ADDRESS->a = data_32_bits;
ADDRESS->b = data_16_bits;
ADDRESS->c = data_8_bits;
ADDRESS->d = data_7_bits;
ADDRESS->e = data_1_bit;
于 2021-11-04T13:07:02.593 に答える