C ++ Я думаю, что мой союз может производить неопределенное поведение - PullRequest
0 голосов
/ 26 декабря 2018

Я использую объединение для представления данных пикселей rgb, поэтому к ним можно обращаться как к непрерывному массиву uint8_t или как к отдельным элементам rgb.(Я думаю, что это, вероятно, одно из немногих применений для союзов.)

Примерно так:

union PixelRGB
{
    uint8_t array[3];
    struct rgb
    {
        uint8_t b;
        uint8_t g;
        uint8_t r;
    };
};

Я фактически взял этот код откуда-то еще в Интернете, который предложил это как потенциальныйиспользуйте.

Я задал вопрос несколько минут назад об отдельной проблеме, но мне сказали, что мой профсоюз может произвести UB.

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

Мой вопрос: почему?

Мое предположение (возможно, неверное)?) в том, что в памяти объединение будет представлено как:

b = array[0]
g = array[1]
r = array[2]

т.е.каждая из этих переменных занимает в памяти одни и те же байты (пробел / местоположение / адрес), и поэтому я бы предположил, что строка

g = 0xff;

изменит значение array[1] на 0xff.

Я не прав?Почему?

Для аргументов: C ++ 14

Повторяющийся вопрос не повторяется: связанный вопрос спрашивает, является ли две структуры внутри объединения UB - не совсем то, что я здесь задаю.

Ответы [ 3 ]

0 голосов
/ 26 декабря 2018

Это неопределенное поведение, явно так в стандарте.Вы не можете написать объединение в одном и читать в другом (применяются исключения) и получить определенное поведение в C ++.

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

0 голосов
/ 26 декабря 2018

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

MyВопрос в том, почему?

Поскольку в стандарте говорится так: 1 .Стандарт иногда навязывает нам (разработчикам на C ++) правила, которые позволяют реализациям (компиляторам) игнорировать крайние случаи и позволяют оптимизировать их для номинального случая.Это такое правило.

Некоторые компиляторы могут создавать двоичный файл, работающий так, как вы ожидаете.Некоторые могут создать аварийный исполняемый файл.Некоторые могут делать что-то среднее или, казалось бы, случайное. Неопределенное поведение не определено 2 .


1)

[class.union]/1

В объединении нестатический элемент данных активен, если его имя относится к объекту, срок жизни которого начался и не закончился ([basic.life]).Не более одного из не статических членов-данных объекта типа объединения может быть активным в любое время, то есть значение не более одного из не-статических членов-данных может быть сохранено в объединении в любое время.

и

[basic.life]/7

Аналогично, до начала срока службы объекта, но после хранения, которое объектЗанятость будет выделена или, после окончания срока службы объекта и до повторного использования или освобождения хранилища, в котором занятый объект, может использоваться любое значение glvalue, которое относится к исходному объекту, но только ограниченным образом.[...] Программа имеет неопределенное поведение, если :

  • для доступа к объекту используется glvalue, или
  • [...]

Чтобы упростить анализ для людей, в следующем контексте:

union { unsigned a; char b[sizeof(unsigned)]; } u;
u.a = 0;       // (1)
(void) u.b[0]; // (2) UB

В строке, помеченной (1), u.a теперь является активным членом u.Согласно [class.union]/1, поскольку только один нестатический член объединения может быть активным одновременно, u.b является не активным.

Это означает, что в строке, отмеченной (2)мы получаем доступ к значению объекта, время жизни которого еще не началось или уже закончилось, что делает его неопределенным поведением по [basic.life]/7.


2)

[defns.undefined]

неопределенное поведение
поведение, для которого данный документ не предъявляет никаких требований

0 голосов
/ 26 декабря 2018

Очевидно, это предположение может зависеть от компилятора.Поэтому я нашел это как альтернативное решение:

class PixelRGB
{

    public:

    unsigned char array[3];
    unsigned char &r;
    unsigned char &g;
    unsigned char &b;

    PixelRGB()
        : r{array[2]}
        , g{array[1]}
        , b{array[0]}
    {
    }
}

Возможно, вам придется следить за своим порядком байтов.Такое очевидное решение.По сути, это программный союз.Недостатком является то, что эта структура использует значительно больше памяти (разве что компилятор может каким-то образом оптимизировать ссылки?), Но это не проблема.Сохраните данные как unsigned char[], а затем используйте их только для манипуляций, что и было моей целью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...