我发现有一段代码实现为类似的演示,如下所示。
struct st
{
int a;
struct
{
int b;
};
};6.58 structs/unions中未命名的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 没有错误,
发布于 2012-11-14 10:29:20
它不必是结构内部的匿名结构,我不认为它很有用:这通常只会通过引入更多的填充来稍微改变布局,而没有其他可见的效果(与将子结构的成员内联到父结构相比)。
我认为匿名结构/联合的优势在其他地方:它们可以用于将匿名结构放置在联合中,也可以用于在结构中放置匿名联合。
示例:
union u
{
int i;
struct { char b1; char b2; char b3; char b4; };
};发布于 2012-11-14 09:55:42
好处很明显,不是吗?它避免了程序员想出一个名字!自从命名是很难的以来,如果没有真正的需求,就可以避免这样做,这是很好的。
这也是一个非常清楚的信号,表明这个struct是本地的,除了作为父结构中的字段之外,从来没有在任何地方使用过,这是非常非常好的信息,因为它减少了不必要的耦合的可能性。
将其视为static;它将内部struct的可见性限制到外部,其方式类似于(但当然不等同于) static如何将全局符号的可见性限制到它们出现的编译单元。
发布于 2016-02-18 23:49:24
我刚刚遇到了匿名union带来的巨大好处。不过,请注意,这不是一个对胆小的人来说的故事,也不是一种推荐的做法。
在一个包含数百个源代码文件的旧C程序中,有一个全局变量struct,它包含一个struct作为成员。因此,全局变量的类型定义如下所示:
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如下:
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。
#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; /* */ \
}; \
};然后使用它,就像这个示例中的三个结构一样,这些结构用于访问从文件中读取的数据记录中的二进制数据。
/* 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 );
}
// .......https://stackoverflow.com/questions/13376494
复制相似问题