【发布时间】:2014-07-03 00:02:38
【问题描述】:
在this question的回复中收到以下声明后:
...您试图覆盖
value和bits,并将数据填充到联合的一个替代方案中并将其从另一个替代方案中取出是未定义。
我对 C99 中的类型双关语允许什么(以及什么是谨慎的)更加好奇。环顾四周后,我在Is type-punning through a union unspecified in C99... 的帖子中发现了很多有用的信息。
从 cmets 和那里发布的答案中可以看出很多东西。为了清楚起见(并作为完整性检查),我想根据我对 C99 标准的理解创建一个示例。下面是我创建的示例代码,虽然它按预期运行,但我想确定我的断言是正确的。
以下代码包含我在 cmets 中的断言。这是我对 C99 中类型双关语的理解。我的cmets正确吗?如果不是,您能解释一下原因吗?
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_BYTES sizeof(uint32_t)
typedef union
{
uint32_t fourByteValue;
uint8_t byteValue[NUM_BYTES];
struct
{
unsigned int firstBitSpecified : 1;
unsigned int secondBitSpecified : 1;
unsigned int thirdBitSpecified : 1;
unsigned int fourthBitSpecified : 1;
unsigned int paddingBits : 4;
uint8_t oneByteStructValue;
uint16_t twoByteStructValue;
};
} U;
int main (void)
{
const char border[] = "==============================\n";
U myUnion;
uint8_t byte;
uint32_t fourBytes;
uint8_t i;
myUnion.fourByteValue = 0x00FFFFFF;
fourBytes = myUnion.fourByteValue; /* 1. This is not type-punning. */
printf("No type-punning fourByteValue:\n%s"
"fourBytes\t= 0x%.4x\n\n", border, fourBytes);
printf("Type-punning byteValue:\n%s", border);
for (i = 0; i < NUM_BYTES; i++)
{
byte = myUnion.byteValue[i]; /* 2. Type-punning allowed by C99,
no unspecified values. */
printf ("byte[%d]\t\t= 0x%.2x\n", i, byte);
}
printf("\n");
myUnion.byteValue[3] = 0xff;
fourBytes = myUnion.fourByteValue; /* 3. Type-punning allowed by C99
but all other 'byteValue's
are now unspecified values. */
printf("Type-punning fourByteValue:\n%s"
"fourBytes\t= 0x%.4x\n\n", border, fourBytes);
myUnion.firstBitSpecified = 0;
myUnion.thirdBitSpecified = 0;
fourBytes = myUnion.fourByteValue; /* 4. Again, this would be allowed, but
the bit that was just assigned
a value of 0 is implementation
defined AND all other bits are
unspecified values. */
printf("Type-punning firstBitSpecified:\n%s"
"fourBytes\t= 0x%.4x\n\n", border, fourBytes);
myUnion.fourByteValue = 0x00000001;
fourBytes = myUnion.firstBitSpecified; /* 5. Type-punning allowed, although
which bit you get is implementation
specific. */
printf("No type-punning, firstBitSpecified:\n%s"
"fourBytes\t= 0x%.4x\n\n", border, fourBytes);
fourBytes = myUnion.secondBitSpecified;
printf("No type-punning, secondBitSpecified:\n%s"
"fourBytes\t= 0x%.4x\n\n", border, fourBytes);
return (EXIT_SUCCESS);
}
以上代码是在 64 位 Windows 7 机器上使用 mingw32-gcc.exe -Wall -g -std=c99 编译的。运行代码后,我收到以下输出:
No type-punning fourByteValue:
==============================
fourBytes = 0xffffff
Type-punning byteValue:
==============================
byte[0] = 0xff
byte[1] = 0xff
byte[2] = 0xff
byte[3] = 0x00
Type-punning fourByteValue:
==============================
fourBytes = 0xffffffff
Type-punning firstBitSpecified:
==============================
fourBytes = 0xfffffffa
No type-punning, firstBitSpecified:
==============================
fourBytes = 0x0001
No type-punning, secondBitSpecified:
==============================
fourBytes = 0x0000
【问题讨论】:
-
请注意,您永远不能依赖位字段的布局顺序。
-
确实如此。这就是为什么我在代码中的 cmets 中对其进行了注释“......刚刚分配的位是实现定义的......”
标签: c c99 language-lawyer