Введите punning в C используя union - PullRequest
4 голосов
/ 11 января 2020

Рассмотрим следующий код:

union u{
    int i;
    long j[2];
};

int main(void){
    union u *u = malloc(sizeof *u);
    u->i = 10;
    printf("%li\n", u->j[0]);
}

Я хочу объяснить законность кода с помощью 6.5:

Объект должен иметь свое хранимое значение, доступ к которому имеет только выражение lvalue, имеющее один из следующих типов:

- тип, совместимый с эффективным типом объекта,

[...]

- агрегат или Тип объединения, который включает один из вышеупомянутых типов среди своих членов (включая, рекурсивно, член субагрегированного или автономного объединения), или

Применяя это к приведенному выше примеру, мы имеем:

  1. u->i = 10; дает объекту u->i эффективный тип int.
  2. lvalue u имеет тип union, который содержит член типа int.
  3. Доступ к объекту u->j[0] с неопределенным значением осуществляется с использованием lvalue u из тип union u, имеющий член типа int.
  4. Применяя кавычку 6.5, мы имеем, что здесь нет UB.

ВОПРОС: Правильно ли такое рассуждение? Или в нем есть какая-то ошибка?

1 Ответ

3 голосов
/ 12 января 2020

Да, ваши рассуждения верны. Это не неопределенное поведение, а неопределенное поведение в соответствии с C11, раздел 6.2.6.1/7:

Когда значение хранится в элементе объекта типа объединения, байты представления объекта которые не соответствуют этому элементу, но соответствуют другим элементам, принимают неопределенные значения.

В разделе 3.19.3 разъясняется, что это означает:

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

Это напоминается в Приложение J: Проблемы переносимости

J.1 Неуточненное поведение 1 Следующее не указано: - ... - Значение байтов заполнения при хранении значений в структурах или объединениях (6.2.6.1). - Значения байтов, которые соответствуют членам объединения, кроме последнего, сохраненного в (6.2.6.1). - ...

В J2 не указано ничего о доступе к членам объединения, что касается неопределенного поведения

При этом проблемы переносимости могут быть серьезными, поскольку в разделе 6.2.6.1/6 напоминается:

Значение структуры или объекта объединения никогда не является представлением ловушек, даже если значение члена структуры или объекта объединения может быть представлением ловушек.

Ловушка представление - это « представление объекта, которое не обязательно должно представлять значение типа объекта » (определение), при этом понимается, что « выборка представления ловушки может выполнить ловушку , но не требуется"(сноска). Таким образом, доступ к неактивному значению может привести к прерыванию программы, но если это не так, то просто нет никаких гарантий на этот счет.

...