UB是否可以访问“填充”字节?

时间:2013-02-06 20:43:10

标签: c++ alignment language-lawyer

如果我有这样一个对象:

struct {
    uint32_t n;
    uint8_t c;
} blob {};

然后会有3个'填充'字节。

UB是否可以访问填充字节? E.g:

uint8_t * data = reinterpret_cast<uint8_t*>(&blob);
std::cout << data[4] << data[5] << data[6] << data[7];

我首先假设这可能是UB,但如果这是真的那么memcpy也会是UB:

memcpy(buf, &blob, sizeof(blob));

我的具体问题是:

  • UB是否可以访问填充字节?
  • 如果不是,那么这是否也意味着定义了值?

4 个答案:

答案 0 :(得分:6)

不,当整个对象被初始化为零时,不是UB访问填充(标准在§8.5/ 5中说,当对象初始化为零时填充初始化为0位)或值初始化时不是具有用户定义构造函数的类。

答案 1 :(得分:0)

我认为,在适当的情况下,你最终可能会遇到UB。我在想的是你有ECC或奇偶校验的内存,其中ecc /奇偶校验位是通过写入内存来设置的。如果在[从未写入AT ALL]之前尚未使用内存块,并且您在填充字段中读取了未初始化的字节,那么当未写入的内存时,可能会导致ecc /奇偶校验错误正在阅读。

当然,在这样一个系统中,你只需在启动过程中的某个时刻做一个“填充所有内存”就可以避免一大堆痛苦,因为这样做会很容易:

struct Blob 
{
    uint32_t n;
    uint8_t c;
};

Blob *b = malloc(sizeof(Blob)*10);

for(int i = 0; i < 10; i++)
{
   b[i].n = i;
   b[i].c = i;
 }


 ...

 Blob a[3];

 memcpy(a, &b[1], sizeof(a));    // Copies 3 * Blob objects, including padding. 

现在,由于并未设置b [x]的所有位,因此可能无法复制memcpy中的数据,因为奇偶校验/ ecc错误。那会非常糟糕。但与此同时,编译器不能强制“设置”所有填充区域。

我的结论是,这是UB,但除非有特殊情况,否则不太可能导致问题。当然,您会在很多代码中看到上述类型的memcpy代码。

答案 2 :(得分:0)

在C中,它不是未定义的行为。您访问未初始化的东西(例如对象中的填充)时唯一一次获得未定义的行为,就是当对象具有自动存储持续时间并且从未进行过地址时

  

6.3.2.1.2:   如果   左值指定了一个自动存储持续时间的对象   声明与寄存器存储类(从未有过其地址)和该对象   未初始化(未使用初始化程序声明,并且没有对其进行任何分配)   在使用之前执行),行为未定义。

但在这种情况下,您正在使用地址(使用&),因此行为定义良好(不会发生错误),但您可能会得到任何随机值。

在C ++中,所有的赌注都是关闭的,通常就是这样。

答案 3 :(得分:0)

POD结构将存在于至少sizeof(struct)字节(包括任何填充字节)的连续内存块中。只有在未首次初始化时,访问填充字节(如果存在)才是UB。

memset(&s, 0, sizeof(s));

这将初始化所有字节,包括填充。之后从填充中读取不会是UB。

当然,memset()是C-ism,我们永远不会在C ++中这样做,对吗?