Неопределенное поведение с объединениями

Работая с 3D-точками, я столкнулся с таким подходом к определению типа:

union point_3d {
    struct {
        GLdouble x, y, z;
    } coord;

    GLdouble tab[ 3 ];
};

Таким образом, к координатам можно получить доступ как по имени, так и по индексу, используя, например, p.coord.x и p.tab.[0] взаимозаменяемо.

Это более полезно, чем просто typedef GLdouble point_3d[3];, поскольку объединения поддерживают прямое присваивание (и, конечно, мы можем получить доступ к координатам по имени), но также более полезно, чем struct point_3d { glDouble x, y, z; };, поскольку тип можно итерировать напрямую без использования sizeof.

Но на самом деле важный вопрос: безопасно ли это? Это портативное? Я не смог найти ничего, что могло бы предположить, что это не так, но я не смог подтвердить, что это гарантировано, поэтому я спрашиваю здесь людей, надеюсь, более знающих, чем я.

(хотя мне интересно узнать, работает ли это в Windows, я конкретно имею в виду переносимость POSIX. Windows имеет для меня лишь второстепенное значение)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

C позволяет каламбур через союзы.

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

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

Я думаю, можно использовать assert, чтобы убедиться, что никакие отступы не пробрались. В C23 static_assert(sizeof(union point_3d) == sizeof(GLdouble[3])); должно быть достаточно.

Ted Lyngmo 01.04.2024 20:33

@TedLyngmo Это слишком строгий тест, поскольку заполнение после членов coord и tab не важно, если оно пробралось. Что-то вроде static_assert(sizeof(point_3d.coord) == sizeof(point_3d.tab),""); - лучший тест.

chux - Reinstate Monica 01.04.2024 21:05

@chux-ReinstateMonica Действительно ли разрешено добавлять поля вокруг массива? Я думал, что размер union foo { type x[X]; } должен быть таким же, как sizeof(type[X]).

Ted Lyngmo 01.04.2024 21:11

@TedLyngmo, рассмотрим union foo { char bar[3]; struct baz { char a,b,c; }; short whiz;}; с потенциальным размером 4 (1 блокнот после .bar/.baz. Размер .bar и .baz равен 3.

chux - Reinstate Monica 01.04.2024 22:58

@chux-ReinstateMonica Правда, это испортило бы день :) Я думал о случаях, когда члены перекрываются 1:1 и имеют одинаковое выравнивание, но, конечно, если другие участники будут с этим возиться, это не сработает .

Ted Lyngmo 01.04.2024 23:08

@TedLyngmo Тот факт, что третий участник может стать катализатором заполнения и, таким образом, демонстрирует, что дополнение возможно в union. Тем не менее, даже для 2: char [3] и char a,b,c нет спецификации, которая не требовала бы заполнения, поэтому заполнение возможно, даже если оно маловероятно. Например, union могут жить в стране с четными адресами.

chux - Reinstate Monica 01.04.2024 23:32

Стандарт C в интерпретации clang и gcc определяет поведение только тогда, когда lvalue имеет форму unionLvalue.member. Даже значения l формы *(unionLvalue.arrayMember+index) не будут последовательно распознаваться как способные идентифицировать то же хранилище, что и другие члены объединения. Я бы не стал доверять clang или gcc для надежной обработки такого кода без использования -fno-strict-aliasing.

supercat 22.04.2024 23:24

Другие вопросы по теме