首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C中未命名的结构/联合有什么好处?

C中未命名的结构/联合有什么好处?
EN

Stack Overflow用户
提问于 2012-11-14 09:54:29
回答 4查看 19.2K关注 0票数 11

我发现有一段代码实现为类似的演示,如下所示。

代码语言:javascript
复制
struct st
{
 int a;
 struct
 {
 int b;
 };
};

6.58 structs/unions中未命名的structs/unions字段

ISO C11所允许。

但是它的好处是什么呢?

因为无论如何,我可以以相同的方式访问数据成员,例如

代码语言:javascript
复制
int main()
{
 struct st s;
 s.a=11;
 s.b=22;
 return 0;
}

在gcc 4.5.2上编的

代码语言:javascript
复制
gcc -Wall demo.c -o demo 

没有错误,

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-11-14 10:29:20

它不必是结构内部的匿名结构,我不认为它很有用:这通常只会通过引入更多的填充来稍微改变布局,而没有其他可见的效果(与将子结构的成员内联到父结构相比)。

我认为匿名结构/联合的优势在其他地方:它们可以用于将匿名结构放置在联合中,也可以用于在结构中放置匿名联合。

示例:

代码语言:javascript
复制
union u
{
  int i;
  struct { char b1; char b2; char b3; char b4; };
};
票数 17
EN

Stack Overflow用户

发布于 2012-11-14 09:55:42

好处很明显,不是吗?它避免了程序员想出一个名字!自从命名是很难的以来,如果没有真正的需求,就可以避免这样做,这是很好的。

这也是一个非常清楚的信号,表明这个struct是本地的,除了作为父结构中的字段之外,从来没有在任何地方使用过,这是非常非常好的信息,因为它减少了不必要的耦合的可能性。

将其视为static;它将内部struct的可见性限制到外部,其方式类似于(但当然不等同于) static如何将全局符号的可见性限制到它们出现的编译单元。

票数 14
EN

Stack Overflow用户

发布于 2016-02-18 23:49:24

我刚刚遇到了匿名union带来的巨大好处。不过,请注意,这不是一个对胆小的人来说的故事,也不是一种推荐的做法。

注:也见在结构中匿名联合,而不是在c99中?

在一个包含数百个源代码文件的旧C程序中,有一个全局变量struct,它包含一个struct作为成员。因此,全局变量的类型定义如下所示:

代码语言:javascript
复制
typedef struct {
    LONG       lAmount;
    STRUCTONE  largeStruct;  // memory area actually used for several different struct objects
    ULONG      ulFlags;
} STRUCTCOMMON;

struct,STRUCTONE,是几个大型结构之一,但在编写此代码时,其他的结构都小于STRUCTONE。因此,这个内存区域,largeStruct被用作一个union,但是没有正确的源语句表示。相反,使用struct将各种memcpy()变量复制到这个区域。更糟糕的是,有时通过全局变量的实际名称,有时通过指向全局变量的指针。

通常情况下,随着时间的推移,最近的变化导致另一个结构成为最大的结构之一。我不得不翻阅上百个文件,寻找它的用途,以及所有的别名和其他所有的东西。

然后我想起了匿名工会。因此,我修改了typedef如下:

代码语言:javascript
复制
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中的匿名

在这个源代码体中,我遇到了一个使用二进制记录的应用程序,该记录可以包含几个不同结构中的一个,这些结构应该是相同长度的。我发现的问题是由于程序员的错误,其中一个结构的大小与其他结构不同。

作为纠正这个问题的一部分,我想要一个解决方案,允许编译器为数据结构找出正确的大小。

由于这些结构在结构的几个成员中包含了一些差异,添加了填充变量以使它们都大小相同,所以我使用了匿名联合,除了其中一个结构外,它们工作得很好。

我发现我可以添加一个匿名结构作为联盟的一部分,这样只要联盟的不同成员和添加的匿名结构有不同的名称,它就可以在Visual 2015中编译。

重要注意事项:此解决方案要求使用Visual 2015的#pragma pack(1)将结构和联合打包到字节边界上。如果不使用pragma,编译器可能会在各种结构和联合中引入未知的填充。

我创建了下面的define,以便标准化匿名union和匿名struct

代码语言:javascript
复制
#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;                           /* */  \
        };  \
    };

然后使用它,就像这个示例中的三个结构一样,这些结构用于访问从文件中读取的数据记录中的二进制数据。

代码语言:javascript
复制
    /* 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;

原本是

代码语言:javascript
复制
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,如下所示:

代码语言:javascript
复制
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;

这些记录格式在代码中使用,类似于以下内容:

代码语言:javascript
复制
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 );
    }

    //    .......
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13376494

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档