Преобразование указателя в проблему длинного переноса в 64-битной среде - PullRequest
2 голосов
/ 15 июня 2011

Я портирую приложение с 32 бит на 64 бит.
Это кодирование в стиле C (устаревший продукт), хотя это C ++. У меня есть проблема, когда комбинация union и struct используется для хранения значений. Здесь используется пользовательский тип данных «Любой», который должен содержать данные любого базового типа данных. Реализация Any выглядит следующим образом:

typedef struct typedvalue
{
long data; // to hold all other types of 4 bytes or less
short id; // this tells what type "data" is holding
short sign; // this differentiates the double value from the rest
}typedvalue;

typedef union Any 
{
double any_any;
double any_double; // to hold double value
typedvalue any_typedvalue;
}Any;

Объединение имеет размер 8 байтов. Они использовали union, чтобы в определенный момент времени было только одно значение, и использовали struct для дифференциации типа. Вы можете хранить значения типа double, long, string, char, float и int в любой момент времени. Это идея. Если это двойное значение, оно сохраняется в any_double. если это любой другой тип, то он хранится в «данных», а тип значения хранится в «идентификаторе». «Знак» скажет, содержит ли значение «Любой» тип double или другой тип. any_any свободно используется в коде для копирования значения в адресном пространстве независимо от типа. (Это наша самая большая проблема, так как мы не знаем в данный момент, что она будет держать!)

Если предполагается, что его строка или указатель «Any» удерживаются, он сохраняется в «data» (который имеет тип long). В 64-х битах, вот где проблема. указатели 8 байтов. Таким образом, нам нужно изменить "long" на эквивалентный 8 байт (long long). Но тогда это увеличит размер объединения до 16 байтов, и либеральное использование «any_any» вызовет проблемы. «Any_any» слишком часто используется, и вы никогда не знаете, что он может содержать.

Я уже пробовал эти шаги, и они оказались неудачными:
1. Изменил в структуре «длинные данные» на «длинные длинные данные», размер объединения составит 16 байтов. - Это не позволит передавать данные как «any_any» (8 байт).
2. Объявил структуру как указатель внутри объединения. И изменил «длинные данные» на «длинные длинные данные» внутри структуры. - проблема здесь заключалась в том, что, поскольку это указатель, нам нужно выделить память для структуры. Либеральное использование «any_any» затрудняет нам выделение памяти. Иногда мы можем перезаписать память и, следовательно, стереть значение.
3. Создайте отдельную коллекцию, в которой будет храниться значение «данные» (пара ключ-значение). - Это не будет работать, потому что эта реализация лежит в основе приложения, сбор данных будет включать миллионы данных.

Кто-нибудь может мне помочь в этом?

Ответы [ 3 ]

1 голос
/ 15 июня 2011

Игнорируя тот факт, что оригинальный дизайн безумен, вы можете использовать <stdint.h> (или скоро <cstdint>, чтобы получить немного предсказуемости:

struct typedvalue
{
  uint16_t id;
  uint16_t sign;
  uint32_t data;
};

union any
{
  char any_raw[8];
  double any_double
  typedvalue any_typedvalue;
};

Вам все еще не гарантируется, что typedvalue будет плотно упаковано, поскольку нет никаких гарантий выравнивания для не char членов. Вы могли бы сделать struct Foo { char x[8]; }; и набрать круг, как *(uint32_t*)(&Foo.x[0]) и *(uint16_t*)(&Foo.x[4])если нужно, но это тоже было бы крайне уродливо.

Если вы находитесь в C ++ 0x, я определенно добавлю статическое утверждение куда-нибудь для sizeof(typedvalue) == sizeof(double).

1 голос
/ 15 июня 2011

«Может ли кто-нибудь помочь мне?», Это звучит как крик отчаяния, и я полностью понимаю его.мобильность, и теперь вы платите цену.

(пусть это будет урок для всех, кто говорит: «Но наша платформа 32-битная! Мы никогда не будем использовать 64-битную!»)

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

0 голосов
/ 15 июня 2011

Если вам нужно хранить как 8-байтовый указатель , так и поле типа, то у вас нет другого выбора, кроме как использовать как минимум 9 байтов, и при 64-битном выравнивании системы, скорее всего, заполнит до 16 байтов.

Ваша структура данных должна выглядеть что-то как:

typedef struct {
    union {
        void   *any_pointer;
        double  any_double;
        long    any_long;
        int     any_int;
    } any;
    char        my_type;
} any;

При использовании C ++ 0x рассмотрите возможность использования строго типизированного перечисления для поля my_type. В более ранних версиях хранилище, требуемое для enum, зависит от реализации и может составлять более одного байта.

Для экономии памяти вы можете использовать (специфичные для компилятора) директивы для запроса оптимальной упаковки структуры данных, но в результате неправильный доступ к памяти может вызвать проблемы с производительностью.

...