编译器是否允许修改填充字节?

5
假设我有这样一段代码(并假设填充是按照我在注释中说的那样插入的):
#include "stdint.h"

struct A
{
    uint8_t x;
    // 3 bytes of padding
    uint32_t y;
};


void foo(struct A* a)
{
    a->x = 0;
}

编译器是否允许清除函数foo中的填充字节或对填充字节进行任何操作?

https://en.cppreference.com/w/c/language/object在这个问题上保持沉默,这让我相信编译器是允许这样做的...

我想知道编译器是否允许这样做的原因是我想比较两个结构体的memcmp,并且我想知道我可以做出什么样的假设...


为什么不直接声明填充呢? - Robert Harvey
您可以假设编译器实现允许添加填充字节,而字节数量可能因版本而异,这被称为ABI更改。通常情况下,您永远不应该使用memcpy来复制结构体,而应该使用默认生成的复制构造函数。在内部,编译器通常会为较大的结构体生成memcpy以进行复制,并在需要时调用构造函数。如果仅使用POD,则无需调用构造函数。与其维护构造函数/析构函数的需要,您应该让编译器独自完成其工作! - Klaus
明确声明填充有一些好处。接替你的程序员不会有刚才你所遇到的同样问题。 - Robert Harvey
@RobertHarvey 但是你无法以可移植的方式实现它。 - Eugene Sh.
如果在您的平台上编写单词比编写字节更有效,则覆盖填充字节似乎是编译器可以执行的合理优化。 - anatolyg
显示剩余2条评论
1个回答

9

是的。C 2018标准6.2.6.1 6条款指出:

当一个值被存储在结构体或联合类型的对象中,包括成员对象时,与任何填充字节对应的对象表示的字节将采用未指定的值……


它是否适用于从一个结构体对象复制到另一个结构体对象的memcpy操作?比如说,memcpy后面跟着一个memcmp会产生非零结果吗? - Eugene Sh.
1
@EugeneSh.:我认为在memcpy之后立即进行memcmp必须表示相等。 - Eric Postpischil
@EricPostpischil 你确定吗?虽然“未指定”意味着编译器供应商可以选择在填充中放置什么,但他们可能选择不覆盖填充字节,因此它们可能包含垃圾。(当然,memcpy将复制垃圾,所以你对memcmp的看法是正确的) - Spencer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接