Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Структуры в 32-битной и 64-битной адресации


Автор: marcusmae 7.8.2008, 18:10
Всем привет,

Подкиньте пожалуйста идеек, а то я уже спёкся : есть, например,

Код

struct A { char* ptr; };


В зависимости от текущего pack-а, размер данной структуры может быть различным на компиляторах разной битности, например, если pack(4), то в 32 битах sizeof будет 4, а в 64 битах - 8. Вопрос : какие есть хорошие способы сделать размер структуры (не конкретно этой, а вообще любой, в т.ч. шаблонной) одинаковым на 32 и на 64 битах? Под хорошими понимаю, что не надо вызывать экскаватор, чтобы полностью перелопатить несколько тысяч строк кода.

Сюда же, есть, например,

Код

struct B { size_t sz; char* ptr; ... };


Здесь уже может бытьразличным не только размер, но и относительное смещение полей структуры. Вопрос : как можно сделать одинаковые смещения (паддинг) для 32 и 64-битного представлений?

Спасибо.

Автор: Mayk 7.8.2008, 18:52
Цитата(marcusmae @  7.8.2008,  22:10 Найти цитируемый пост)

Здесь уже может быть различным не только размер, но и относительное смещение полей структуры. Вопрос : как можно сделать одинаковые смещения (паддинг) для 32 и 64-битного представлений?


1) все int'ы, long'и и тд заменить на int32_t, int64_t, т д, определенные в inttypes.h и/или stdint.h
2) Вместо указателей использовать uint64_t, который кастовать к указателю в случае надобности 
3) а нафига?

про выравнивание  не скажу ибо не юзал (см п. 3))

Автор: Любитель 7.8.2008, 19:20
Цитата(Mayk @  7.8.2008,  18:52 Найти цитируемый пост)
3) а нафига?

Для бинарной совместимости сохраняемых данных, я думаю smile Сохранили на одной машине - можем загрузить на другой. Или пересылка по сети - не суть важно

Автор: bsa 7.8.2008, 21:58
Цитата(Любитель @ 7.8.2008,  19:20)
Цитата(Mayk @  7.8.2008,  18:52 Найти цитируемый пост)
3) а нафига?

Для бинарной совместимости сохраняемых данных, я думаю smile Сохранили на одной машине - можем загрузить на другой. Или пересылка по сети - не суть важно

А что, указатель полученный по сети является валидным  smile 
Лично мне тоже не понятно, зачем куда-то сохраняться/пересылать указатели. Если в пределах одного процесса, то нет вообще никаких проблем с бинарной совместимостью. А если между разными, то по любому надо передавать данные, а не указатели на них.

Автор: marcusmae 7.8.2008, 22:36
Друзья, речь идёт о процессоре Cell, который сидит например в PlayStation3 :

user posted image

Головной PowerPC имеет 64-битную адресацию, сопроцессоры - сокращённую 32-битную. Если из памяти основного процессора переслать на сопроцессор структуру, содержающую поля-указатели, то на сопроцессоре они перестанут быть валидны, т.к. будут иметь другую длину, а сама структура будет иметь неверный sizeof - всё сломается. Конечно, остаться без решения шансов нет никаких, как раз в этом духе

Цитата(Mayk @  7.8.2008,  18:52 Найти цитируемый пост)
2) Вместо указателей использовать uint64_t, который кастовать к указателю в случае надобности 


и предлагается действовать, причём безотносительно специфики кода - представьте сколько времени займут такие преобразования в большой программе.

Я намеренно не писал об архитектуре, поскольку цель вопроса именно в поиске языковых возможностей. Что можно сделать для того чтобы в 32-битном представлении указатель располагался в структуре, как 4 байта и затем следовала бы 4-байтовая дырка, а в 64-битном - как полные 8 байтов? В принципе, имея это, уже видно, что делать. Подскажите, пожалуйста.

Автор: bsa 7.8.2008, 23:43
Если пишется на C++, то можно сварганить шаблон типа:
Код
template<typename Type>
class Pointer
{
public:
    Pointer(Type *value = 0) : value_(value){}
...
private:
    Type *value_;
#ifndef POINTER_IS_64_BIT
    char dummy[4];
#endif //POINTER_IS_64_BIT
};


Кстати, а адресное пространство у процессов выполняющихся на разных ядрах этого процессора одинаковое? Там точно можно просто касты делать?

Автор: marcusmae 8.8.2008, 00:14
bsa, спасибо, вот я сварганил ещё один вариант :

Код

struct Test
{
    char byte;

    // ...

    union {
        char * spe;
        unsigned long long ppe;
    } ptr;
} test;

#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    using namespace std;

    cout << "sizeof(test) = " << sizeof(test) <<
        " sizeof(ptr.spe) = " << sizeof(test.ptr.spe) <<
        " sizeof(ptr.ppe) = " << sizeof(test.ptr.ppe) << endl;

    cin.get();

    return 0;
}


Под рукой M$VC :

Цитата

Win32 : sizeof(test) = 16 sizeof(ptr.spe) = 4 sizeof(ptr.ppe) = 8
x64 : sizeof(test) = 16 sizeof(ptr.spe) = 8 sizeof(ptr.ppe) = 8


ну и sizeof(ptr) = 8 в обоих случаях, char byte - для массовки

Похоже, что результат достигается.

А ещё лучше можно? Чтобы вообще минимум изменений в код или макросами и прагмами?

Автор: bsa 8.8.2008, 00:21
вряд ли...
Если пишешь на С++, то можно вместо указателей использовать шаблон "указатель" (который я привел), определив все необходимые методы. Тогда ограничишься правкой только объявлений структур/классов.

Автор: marcusmae 8.8.2008, 00:30
Цитата(bsa @  7.8.2008,  23:43 Найти цитируемый пост)
Кстати, а адресное пространство у процессов выполняющихся на разных ядрах этого процессора одинаковое? Там точно можно просто касты делать?


На сопроцессорах вроде бы одинаковое, но пожалуй это не принципиально. Подход следующий : выделяем локальную память под структуру и перекачиваем туда экземпляр из памяти мастера. В этом экземпляре готовенькие только поля-значения, а поля-указатели ссылаются на адреса в памяти мастера. Необходимо же получить на сопроцессоре полную копию структуры, считая reference-данные. Так что снова выделяем память и перекачиваем данные с этих адресов. Ну и завершающий шаг : теперь, когда ссылочное хозяйство стало локальным, нужно поменять в локальном же экземпляре структуры адреса с мастеровых на локальные. Далее с этой структурой можно работать как ни в чём не бывало smile

Цитата(bsa @  8.8.2008,  00:21 Найти цитируемый пост)
Если пишешь на С++, то можно вместо указателей использовать шаблон "указатель" (который я привел), определив все необходимые методы. Тогда ограничишься правкой только объявлений структур/классов.


Да, пожалуй.

Автор: marcusmae 8.8.2008, 11:36
А может быть так :

Код

#ifdef _SPE
#define CROSS_PTR(varname, ...) __VA_ARGS__ *varname, *ext_##varname
#else
#define CROSS_PTR(varname, ...) __VA_ARGS__ *varname
#endif


?

Автор: bsa 8.8.2008, 13:21
имхо, это сложнее и синтаксис будет менее красивым, нежели с шаблоном...

Автор: marcusmae 8.8.2008, 13:41
Цитата(bsa @  8.8.2008,  13:21 Найти цитируемый пост)
имхо, это сложнее и синтаксис будет менее красивым, нежели с шаблоном...


почему сложнее?

Код

CROSS_PTR(ptr, char);


даст

Код

char *ptr, *ext_ptr;


а у Вас будет

Код

Pointer<char> pchar;


- составной объект - до указателя нужно ещё добраться.

синтаксис конечно выглядит более естественно smile 


Автор: bsa 8.8.2008, 17:17
Цитата(marcusmae @ 8.8.2008,  13:41)
синтаксис конечно выглядит более естественно smile

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)