Приведение большого POD в маленькое POD - гарантированно сработает? - PullRequest
1 голос
/ 03 сентября 2011

Предположим, у меня есть структура POD, которая имеет более 40 членов.Эти члены не являются встроенными типами, скорее, большинство из них являются структурами POD, которые, в свою очередь, имеют много членов, большинство из которых снова являются структурами POD.Этот шаблон подходит ко многим уровням - POD имеет POD, имеет POD и т. Д. - даже до 10 или около того уровней.

Я не могу опубликовать фактический код, поэтому вот один очень простой пример этого шаблона:

//POD struct
struct Big  
{
    A a[2];  //POD has POD
    B b;     //POD has POD
    double dar[6];
    int m;
    bool is;
    double d;
    char c[10];
};

И A и B определены как:

struct A
{
    int i;
    int j;
    int k;
};

struct B
{
    A a;   //POD has POD 
    double x;
    double y;
    double z;
    char *s;
};

Это действительно очень упрощенная версия фактического кода, который был написан (на C) почти 20 лет назад Citrix Systems , когда они разработали протокол ICA .За прошедшие годы код сильно изменился.Теперь у нас есть исходный код, но мы не можем знать, какой код используется в текущей версии ICA, а какой был отброшен, так как отброшенная часть также присутствует в исходном коде.

То естьпредыстория проблемы.Проблема в том, что теперь у нас есть исходный код, и мы строим систему на основе протокола ICA, для которой в какой-то момент нам нужно знать значения нескольких членов большой структуры,Мало членов, не все.К счастью, эти члены появляются в начале структуры, поэтому мы можем написать структуру, которая является частью большой структуры, как:

//Part of struct B 
//Whatever members it has, they are in the same order as they appear in Big.
struct partBig
{
    A a[2];
    B b;
    double dar[6];
    //rest is ignored
};

Теперь предположим, что мы знаем указатель наBig struct (которую мы знаем путем расшифровки протокола и потоков данных), затем мы можем написать это:

Big *pBig = GetBig(); 
partBig *part = (partBig*)pBig; //Is this safe?
/*here can we pretend that part is actually Big, so as to access 
first few members safely (using part pointer), namely those 
which are defined in partBig?*/

Я не хочу определять всю структуру Big в нашем коде, какв нем слишком много членов POD, и если я определю структуру целиком, я сначала определю сотни других структур.Я не хочу этого, так как даже если я это сделаю, я сомневаюсь, что смогу сделать это правильно, поскольку я не знаю все структуры правильно (относительно того, какая версия используется сегодня, а какая отвергнута).

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

Буду благодарен за соответствующие ссылки из спецификации языка.: -)

Вот демоверсия такого кастинга: http://ideone.com/c7SWr

Ответы [ 4 ]

5 голосов
/ 03 сентября 2011

Спецификация языка имеет некоторые функции, которые похожи на то, что вы пытаетесь сделать: 6.5.2.3/5 гласит, что если у вас есть несколько структур, которые разделяют общую начальную последовательность членов, вы можетепроверять этих общих членов через любой структур в союзе, независимо от того, какой из них в настоящее время активен.Таким образом, из этой гарантии можно легко вывести, что структуры с общей начальной последовательностью элементов должны иметь одинаковую структуру памяти для этих общих элементов.

Однако язык, похоже, явно не позволяет делатьто, что вы делаете, то есть переосмысление одного объекта структуры как другого не связанного объекта структуры посредством приведения указателя.(Язык позволяет получить доступ к первому члену объекта структуры через приведение указателя, но не к тому, что вы делаете в своем коде).Таким образом, с этой точки зрения то, что вы делаете, может быть нарушением строгого псевдонима (см. 6.5 / 7).Хотя я не уверен в этом, так как мне не сразу понятно, было ли намерение 6.5 / 7 преследовать этот вид доступа вне закона.

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

3 голосов
/ 03 сентября 2011

Да, если ваша маленькая конструкция имеет те же правила упаковки / заполнения, что и большая, все будет в порядке.Порядок расположения в памяти полей в структуре четко определяется языковыми спецификациями.

0 голосов
/ 05 сентября 2011

Соответствующим правилом псевдонимов типов является 3.10 / 10: «Если программа пытается получить доступ к сохраненному значению объекта через glvalue другого, чем один из следующих типов, поведение не определено: ...».

Список содержит два относящихся к нам случая:

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

Первый случайнедостаточно: это просто охватывает cv-квалификации.Второй случай допускает при взломе union то, что упоминает AndreyT (общая начальная последовательность), но ничего больше.

0 голосов
/ 03 сентября 2011

Единственный способ получить BigPart от Big - это использовать reinterpret_cast (или стиль C, как в вашем вопросе), и стандарт не определяет, что происходит в этом случае.Тем не менее, он должен работать как ожидалось.Вероятно, он потерпит неудачу только для некоторых супер экзотических платформ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...