Присвоение имен элементам массива или структура и массив в союзе - PullRequest
10 голосов
/ 23 июня 2011

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

struct Vector4D
{
   union
   {
      double components[4];
      struct { double x, y, z, t; } Endpoint;
   };
};

Мне кажется, что я видел нечто подобное в структуре WinApi IPAddress.Идея состоит в том, чтобы дать мне возможность использовать компоненты массива как по индексу, так и по имени, например:

Vector4D v;
v.components[2] = 3.0;
ASSERT(v.Endpoint.z == 3.0) //let's ignore precision issues for now

В стандарте C ++ есть гарантия того, что на пустом месте не будетначало POD-структуры, то есть элемент x будет расположен прямо в начале структуры Endpoint.Хорошо до сих пор.Но я, похоже, не нахожу никаких гарантий того, что между x и y, или y и z и т. Д. Не будет пустого пространства или отступов, и т. Д. Я не проверилстандарт C99.

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

Вопросы:

  1. Прав ли я, что действительно нет гарантии, что это будет работать ни в C, ни в C ++.

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

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

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

Ответы [ 4 ]

5 голосов
/ 23 июня 2011
  1. да
  2. зависит от требований к архитектуре и стратегии компиляции
  3. нет, но вы можете сделать обертку для объекта (но в итоге вы получите .z()вместо просто .z)

Большинство компиляторов должны поддерживать сжатие структуры с использованием прагмы или атрибута.#pragma pack например.

4 голосов
/ 23 июня 2011

Вы можете обойти любые проблемы с выравниванием памяти, имея ссылки на каждый элемент массива, если вы объявляете массив перед ссылками в классе, чтобы убедиться, что они указывают на действительные данные.Сказав, что я сомневаюсь, что выравнивание будет проблемой с двойными числами, но может быть и для других типов (возможно, с плавающей запятой на 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;
}

Надеюсь, это поможет.

2 голосов
/ 23 июня 2011

Когда речь идет о стандарте, есть две проблемы с ним:

  • Не указано, что происходит при записи элемента в объединении и чтении из другого, см. Стандарт C 6.2.6.1 и K.1
  • Стандарт не гарантирует, что компоновка структуры соответствует компоновке массива, подробнее см. Стандарт C 6.7.2.1.10.
* 1008Сказав это, на практике это будет работать на обычных компиляторах.Фактически, этот вид кода широко распространен и часто используется для переинтерпретации значений одного типа в значения другого типа.
0 голосов
/ 23 июня 2011

Заполнение байтов не вызовет проблемы, так как все переменные имеют тип double. Компилятор будет обрабатывать Vector4D как массив double. Это означает, что v.Endpoint.z по существу совпадает с v[2].

...