Именование элементов массива или структуры и массива в объединении
рассмотрим следующую структуру:
struct Vector4D
{
union
{
double components[4];
struct { double x, y, z, t; } Endpoint;
};
};
мне кажется, что я видел что-то подобное в структуре IPAddress WinApi. Идея состоит в том, чтобы дать мне возможность использовать компоненты массива как по индексу, так и по имени, например:
Vector4D v;
v.components[2] = 3.0;
ASSERT(v.Endpoint.z == 3.0) //let's ignore precision issues for now
в стандарте C++ есть гарантия, что в начале подструктуры не будет "пустого" пространства, то есть элемент x будет расположен прямо в начале структуры конечной точки. Пока все хорошо. Но Кажется, я не нахожу никаких гарантий, что между x
и y
или y
и z
, etc. Однако я не проверил стандарт C99.
проблема в том, что если есть пустое пространство между элементами конечной структуры, то идея не будет работать.
вопросы:
Я прав, что действительно нет никакой гарантии, что это сработает либо на C, либо на C++.
будет ли это работать практически на любой известной реализации? Другими словами, Знаете ли вы о какой-либо реализации, где это не работает?
есть ли какой-либо стандартный(я имею в виду не специфичный для компилятора) способ выразить ту же идею? Может быть, функции выравнивания C++0x могут помочь?
кстати, это не то, что я делаю в производственном коде, не волнуйтесь, просто любопытно. Спасибо продвижение.
4 ответов
- да
- зависит от потребностей выравнивания архитектуры и стратегии компиляторов
- нет, но вы можете сделать обертку объекта (но вы получите просто
.z
)
большинство компиляторов должны поддерживать сжатие структуры с помощью pragma или атрибута. #pragma pack
например.
вы можете обойти любые проблемы выравнивания памяти, имея ссылки на каждый элемент массива, если вы объявляете массив перед ссылками в классе, чтобы убедиться, что они указывают на допустимые данные. Сказав, что я сомневаюсь, что выравнивание будет проблемой с двойниками, но может быть для других типов (возможно, float на 64-битной арке?)
#include <iostream>
using namespace std;
struct Vector4D
{
Vector4D() : components(), x(components[0]), y(components[1]), z(components[2]), t(components[3]) { }
double components[4];
double& x;
double& y;
double& z;
double& t;
};
int main()
{
Vector4D v;
v.components[0] = 3.0;
v.components[1] = 1.0;
v.components[2] = 4.0;
v.components[3] = 15.0;
cout << v.x << endl;
cout << v.y << endl;
cout << v.z << endl;
cout << v.t << endl;
}
надеюсь, что это помогает.
когда дело доходит до стандарта, есть две проблемы с ним:
- не указано, что происходит при записи элемента в объединение и чтении из другого, см. стандарт C 6.2.6.1 и K. 1
- стандарт не гарантирует макет матч структуру, макет массива, см. стандарт C 6.7.2.1.10 для деталей.
сказав это, на практике это будет работать на нормальных компиляторах. По сути, этот вид код широко распространен и часто используется для переинтерпретации значений одного типа В значения другого типа.
байты заполнения не вызовут проблемы, поскольку все переменные имеют тип double
. Компилятор обработает Vector4D
как double
массив. Это значит,v.Endpoint.z
по существу то же самое, что v[2]
.