通过POD结构

时间:2018-11-28 07:11:18

标签: c++ c++14 standard-layout

我找到了一些代码,并希望确保自己正确理解。 用例是由值数组表示的打包图像。 在此示例中,三个值代表一个像素。

我发现的代码是这样的:

struct Pixel{ 
  int[3] data
  int x(){return data[0];}
  int y(){return data[1];}
  int z(){return data[2];}
};

void main(){

  std::vector<int> img(300);
  Pixel* access = reinterpret_cast<Pixel*>(img.data()+3*5);
  foo(access->x());
}

从阅读POD and standard layout可以理解,我认为代码示例是有效的,因为我们仅使用Pixel的第一个成员? 然后将Pixel替换为

struct Pixel2{
  int red;
  int green;
  int blue;
};

会导致不确定的行为吗?

编辑: 我与cuda合作,发现了另一个示例: 将无符号char指针(数组)转换为uchar3指针。 uchar3类型定义等于第二个像素定义。 这是否表示秒也有效? 还是这仅适用于nvcc编译的代码? 如果第二个Pixel定义有效,为什么?

编辑: 为了进一步强调代码的作用,我在上面重命名了一些字段: 我有一系列原始数据。就我而言,这是一个打包的图像。我想拥有一种访问像素及其值的好方法。所以我可以做这样的事情:

void bar(int* data,size_t size)
{
   Pixel2* img = reinterpret_cast<Pixel*>(data);
   std::cout << "Pixel 13 has blue value: " << img[13].blue;
}

我已经看到在cuda中使用此代码的代码并且可以正常工作,但是我想知道它是否仍然可以,因为我所读到的关于POD的内容似乎没有涵盖它。 我只是错过了一些有关POD的东西,还是会失败的东西?

编辑: 之间有区别吗?

  foo(access->x());
  foo(access->data[0]);

我认为第二个应该合法,因为对于POD类型,第一个成员变量具有与对象相同的地址?

编辑:我从答案中得到的是:在我提到的所有情况下,都是UB。 这样的方式将是为我提供所需的访问权限的随机访问迭代器。

2 个答案:

答案 0 :(得分:1)

在不存在的对象上调用非静态成员函数并对不存在的对象上的非静态数据成员执行类成员访问都是未定义的行为。

您的代码中没有任何内容可以创建PixelPixel2对象。

答案 1 :(得分:0)

我在这里可能是完全错误的,但对我来说,您的两个结构实际上都是UB。但是,这种情况不太可能发生。

(不太可能的)用例可能会造成一定的伤害,即向量的对齐方式(例如,可以从库中提供)和结构不同时。如果代码是使用相同的编译器和相同的设置编译的,除非您自己对齐,否则应该不会发生。考虑到向量的对齐方式不同,两个结构都将导致UB。或您的结构对齐方式不同,在此相同,UB。但是,未定义的行为不是来自对齐,而是来自reinterpret_cast对此一无所知的事实。

作为一个简单而肮脏的例子:

struct Pixel2 {
    alignas(8) int red;
    alignas(8) int green;
    alignas(8) int blue;
};

会给您错误的像素值。使用int数组的结构也可以做到这一点。

See this example ,您可以在这里玩耍。在这里,两个结构都无法获取正确的值。对于向量的对齐方式不同的变体,请替换第69/70行上的注释(将std::vector<int> data;替换为static_vector<int, 128> data;)。

一些值得一提的答案: