Понимание примера кода с reinterpret_cast из POD-структуры - PullRequest
0 голосов
/ 28 ноября 2018

Я нашел некоторый код и хочу убедиться, что я правильно понимаю.Вариант использования - это упакованное изображение, которое представлено массивом значений.В этом примере три значения представляют один пиксель.

Код, который я нашел, выглядит примерно так:

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 и нашел другой пример: приведение и беззнаковый указатель 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 или это что-то, что может дать сбой?

Редактировать: Есть ли разница между:

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

Я думал, что секунда должна быть законной, поскольку для типов PODПервая переменная-член имеет тот же адрес, что и объект?

Редактировать: Что я беру из ответов: это UB во всех случаях, которые я упомянул.Тогда можно было бы использовать итератор с произвольным доступом, который дает мне доступ, который мне нужен.

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Вызов нестатической функции-члена для несуществующего объекта и выполнение доступа к элементу класса для нестатического члена-данных для несуществующего объекта являются неопределенным поведением.

Ничто в вашем коде не создает Pixel или Pixel2 объект.

0 голосов
/ 28 ноября 2018

Я могу ошибаться, но мне кажется, что ваша структура на самом деле 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:

...