2

我找到了一些代码,并想确保我正确理解了这一点。用例是由值数组表示的打包图像。在本例中,三个值代表一个像素。

我找到的代码是这样的:

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 和标准布局中了解到的那样,我认为代码示例是有效的,因为我们只使用了 Pixel 的第一个成员?然后将 Pixel 替换为

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

会导致未定义的行为吗?

编辑:我使用 cuda 并找到了另一个示例:将无符号字符指针(一个数组)转换为 uchar3 指针。uchar3 类型定义等于第二个像素定义。这是否意味着第二个也有效?还是这仅适用于 nvcc 编译的代码?如果第二个像素定义是有效的,那为什么?

编辑:为了进一步强调代码试图做什么,我重命名了上面的一些字段:我有一个原始数据数组。在我的情况下,这是一个打包的图像。我想要一种访问像素及其值的好方法。所以我可以做这样的事情:

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。那么要走的路将是一个随机访问迭代器,它给我我想要的访问权限。

4

2 回答 2

1

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

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

于 2018-11-28T19:07:23.390 回答
0

我在这里可能完全错了,但在我看来,你的两个结构实际上都是 UB。但是,这不太可能发生。

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

作为一个快速而肮脏的例子:

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

会给你错误的像素值。使用 int 数组的结构也可以这样做。

请参阅此示例,您可以在其中玩耍。在这里,两个结构都无法获得正确的值。对于向量对齐方式不同的变体,请替换第 69/70 行的注释(替换std::vector<int> data;static_vector<int, 128> data;)。

一些可提及的 SO 答案:

于 2018-11-28T10:37:28.293 回答