首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么存储在struct和union对象中的值对应于任何填充字节,并接受未指定的值?

为什么存储在struct和union对象中的值对应于任何填充字节,并接受未指定的值?
EN

Stack Overflow用户
提问于 2017-11-10 12:32:50
回答 3查看 152关注 0票数 1

来自C11标准

我刚刚阅读了C11标准中的内容,无法理解为什么存储在结构/联合对象中的值,填充字节的对象表示采用未指定的值?

我知道标准没有规定任何要求的具体方法。

当值存储在结构或联合类型的对象(包括成员对象)中时,与任何填充字节对应的对象表示的字节将接受未指定的值。 结构或联合对象的值绝不是陷阱表示,即使结构或联合对象的成员的值可能是陷阱表示。

有人能给我举个例子来更好地理解这句话吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-11-10 14:46:21

基本上是这样的:

  • 要为成员获得正确的对齐方式,struct/union需要填充字节。编译器会根据自己的意愿自动插入这些内容。
  • C委员会没有对填充字节的值提出任何要求。这是故意的,这样程序就不需要在初始化或复制结构时写入填充字节。如果标准要求填充字节具有例如值为零的值,那么这将引入一种非常轻微的执行开销。 (这一微乎其微的潜在性能增益就是为什么结构将所有这些晦涩的机制连接在一起的原因。这确实是C的精神--如果我们能以混淆和不一致为代价,使某些东西变得更快,那么就让它变得更快。)
  • 然而,C也允许外来的系统有陷阱表示-特定的位序列,将产生运行时异常的某种类型,无论何时被读取。如果允许填充字节具有任何值,则它们可能最终成为陷阱表示。因此,有一个例外说填充字节可能有任何值,但没有陷阱表示的值。

因此:您不能信任填充字节具有任何给定的值(除了它们不能是陷阱表示)。填充字节的值可能因情况不同而不同--不能保证它们的值是一致的。

考虑一个没有陷阱表示的普通32位二位补码系统:

代码语言:javascript
运行
复制
typedef struct
{
  uint8_t  u8;
  uint32_t u32;
} something_t;

something_t thing1 = {1, 2};
something_t thing2 = {3, 4}

在这里,一个可能的内存布局是这样的(十六进制,小endian):

代码语言:javascript
运行
复制
01 AA BB CC 02 00 00 00  // thing 1
03 55 66 77 04 00 00 00  // thing 2
^  ^        ^
u8 padding  u32

在thing1中,01是u8成员,AA BB CC序列是填充字节的未指定值,02 00 00 00是u32成员。

如果我们现在编写thing1 = thing2,编译器可以执行以下操作之一:

  • 复制整个thing2并覆盖所有thing1,包括填充,如果这是最有效的,
  • 或者,如果效率更高,则复制u8u32,但不要写入填充字节,使它们保持原样,从而导致thing1现在具有内存布局03 AA BB CC 04 00 00 00

这就是为什么我们不能将结构与==运算符或像memcmp()这样的函数进行比较的原因。

票数 4
EN

Stack Overflow用户

发布于 2017-11-10 12:38:51

假设sizeof(long)=8sizeof(int)=4,64位机器:

代码语言:javascript
运行
复制
struct {
    int a;
    long b;
} obj = {0, 0};

&obj.a&obj.b之间有4个字节的填充是有意义的。填充物的内容应该是什么?为什么强迫运行时在那里放置任何东西?obj的布局也可以是0x00000000, 0xDEADBEEF, 0x00000000, 0x00000000 --即4字节的垃圾,因为不需要访问它们(因此不应该访问它们)。

通常情况下,问题是相反的--如果您认为应该指定它(也就是说,您希望迫使编译器编写人员做更多的工作,以及可能效率较低的工作),那么应该由您来解释原因。

票数 3
EN

Stack Overflow用户

发布于 2017-11-10 12:34:50

问题是,你永远不知道结构或结合的元素在记忆中是如何事先被确定的。所述填充位可因系统而异。

此外,还可以考虑编译器对此的处理方法。所实现的布局优化是不同的。在某些编译器中,它将是一个,然后在另一个编译器中有所不同。

陷阱表示是适合于类型占用空间的位模式,但如果用作该类型的值,则会触发未定义的行为。

例如:-

代码语言:javascript
运行
复制
struct a{
   int a;
   char b;
};

在这里,结构的大小不一定是ab的大小。填充正在添加,这是标准的事情,不评论。您希望将结构作为一个整体来处理,表示可以工作。但是,如果要以严格的8字节表示形式访问元素,则可能会失败。

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

https://stackoverflow.com/questions/47222888

复制
相关文章

相似问题

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