Именование элементов массива или структуры и массива в объединении

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

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.

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

вопросы:

  1. Я прав, что действительно нет никакой гарантии, что это сработает либо на C, либо на C++.

  2. будет ли это работать практически на любой известной реализации? Другими словами, Знаете ли вы о какой-либо реализации, где это не работает?

  3. есть ли какой-либо стандартный(я имею в виду не специфичный для компилятора) способ выразить ту же идею? Может быть, функции выравнивания C++0x могут помочь?

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

4 ответов


  1. да
  2. зависит от потребностей выравнивания архитектуры и стратегии компиляторов
  3. нет, но вы можете сделать обертку объекта (но вы получите просто .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].