Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Размещение структур в памяти

501
17 ноября 2004 года
hell_admin
110 / / 02.10.2004
Вопрос может показаться глупым, но никогда до этого не сталкивался с записью структур или классов с членами-функциями в файл, вот и интерестно как отработает такой код:

struct A
{
char s[256];
void somefunc();
char s2[1024];
... // другие функции
}

При записи структуры в файл:
A str;
...
FILE* f = fopen("file", "wb");
fwrite((char*)&str, sizeof(str), 1, f);
..
Ну и загрузке в обратном порядке:

Т.е. простыми словами что запишется в файл, только члены-переменные или еще чего-то от функций ???
831
17 ноября 2004 года
S_T
117 / / 23.10.2002
Цитата:
Originally posted by hell_admin
Вопрос может показаться глупым, но никогда до этого не сталкивался с записью структур или классов с членами-функциями в файл, вот и интерестно как отработает такой код:

struct A
{
char s[256];
void somefunc();
char s2[1024];
... // другие функции
}

При записи структуры в файл:
A str;
...
FILE* f = fopen("file", "wb");
fwrite((char*)&str, sizeof(str), 1, f);
..
Ну и загрузке в обратном порядке:

Т.е. простыми словами что запишется в файл, только члены-переменные или еще чего-то от функций ???



От функций ничего не запишется. Запишутся только значения переменных.
То есть в твоем случае в файл пойдет (1024 + 256) * sizeof(char) байт.
В данном случае если загружать подобным образом, то будет все ОК.
Только не забудь, если у тебя будут member'ы у структуры вида char* m_pStr; и ты где то будешь писать m_pStr = new char[100]; То в файл у тебя запишется только значение указателя (то есть 4 байта, а не 100 байт - на которые этот указатель указывает). Так что при загрузке из файла такие member'ы будут содержать в себе мусор.

1.9K
17 ноября 2004 года
solovey
113 / / 25.07.2004
Цитата:
Originally posted by hell_admin
Вопрос может показаться глупым, но никогда до этого не сталкивался с записью структур или классов с членами-функциями в файл, вот и интерестно как отработает такой код:

struct A
{
char s[256];
void somefunc();
char s2[1024];
... // другие функции
}

При записи структуры в файл:
A str;
...
FILE* f = fopen("file", "wb");
fwrite((char*)&str, sizeof(str), 1, f);
..
Ну и загрузке в обратном порядке:

Т.е. простыми словами что запишется в файл, только члены-переменные или еще чего-то от функций ???


ниче он незапишет, т.к. ты не определил оператор (char*). А вообще, лучше к своей структуре добавь функцию bool WriteToFile(YourMegaStruct & X)
{
/* твой код */
}

3
17 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by S_T

От функций ничего не запишется. Запишутся только значения переменных.



Ну почему же...
Запишутся указатели на виртуальные таблицы и пр. служебная информация.

527
17 ноября 2004 года
pavor
275 / / 28.09.2003
Цитата:
Originally posted by Green


Ну почему же...
Запишутся указатели на виртуальные таблицы и пр. служебная информация.


Запишутся только если он выйдет за границы данных.

527
17 ноября 2004 года
pavor
275 / / 28.09.2003
Цитата:
Originally posted by solovey

ниче он незапишет, т.к. ты не определил оператор (char*)


Спорим на 5 баков?

501
17 ноября 2004 года
hell_admin
110 / / 02.10.2004
Цитата:
Originally posted by pavor

Спорим на 5 баков?



Мне Процент, Я же тему начал :D, хотя мне ладно мне хватит просто окончательного ответа запишет ли чего или нет, например всякие там vtbl.

527
17 ноября 2004 года
pavor
275 / / 28.09.2003
Цитата:
Originally posted by hell_admin


Мне Процент, Я же тему начал :D, хотя мне ладно мне хватит просто окончательного ответа запишет ли чего или нет, например всякие там vtbl.


Ты пробовал провести эксперимент? Не обязательно записывать в файл данные. Достаточно просто посчитать размер предполагаемый и сравнить его с возвращаемым sizeof. Если данные выровнены на 4 байта, то гарантированно при совпадении размеров совпадут и данные.

501
18 ноября 2004 года
hell_admin
110 / / 02.10.2004
Цитата:
Originally posted by pavor

Ты пробовал провести эксперимент? Не обязательно записывать в файл данные. Достаточно просто посчитать размер предполагаемый и сравнить его с возвращаемым sizeof. Если данные выровнены на 4 байта, то гарантированно при совпадении размеров совпадут и данные.



Я уже попробывалб размеры вроде совпадают, интерестно что про это говорит стандарт?

И как сделать что бы не зависело от выравнивания компилятора?

3
18 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by pavor

Запишутся только если он выйдет за границы данных.



Что бы это значило "границы данных"?

Указатели на vtbl находятся в начале экземпляра класса (и в начале каждой части экземпляра класса потомка для множественного наследования).

 
Код:
struct A
{
    int data;
    virtual void func() {}
};

A str;
A* pA = &str;

pA будет указывать не на данные (int data), а на vfptr (указатель на vtbl), а размер класса sizeof(A)=8: sizeof(vfptr) + sizeof(data).

Т.о.
fwrite((char*)&str, sizeof(str), 1, f);
запишет 8 байт информации, первые 4 из которых - vfptr

Так что ты имел в виду своей фразой про "границы данных"?! :}
3
18 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by hell_admin

Я уже попробывалб размеры вроде совпадают, интерестно что про это говорит стандарт?


Про что ты хочешь узнать из стандарта?
Сформулируй вопрос, плз.

Цитата:
Originally posted by hell_admin

И как сделать что бы не зависело от выравнивания компилятора?


#pragma pack(1)
struct A
{
};
#pragma pack()


Вот только сохранение таким способом, как ты пытаешься сделать неверное. Оно приведет к ошибкам, точнее к потере информации в первую очередь, если:
1) класс содержит указатели, т.к. они станут невалидными при повторном запуске приложения;
2) класс содержит виртуальные методы или порожден от классов, содержащих виртуальные методы;
3) класс агрегирует другие сложные классы (под сложными будем понимать классы которые могут соотв. этим перечисленным условиям).

Т.о. есть смысл подобным образом сохранять лишь простейшие структуры данных, т.е. содержащие только фундаментальные типы данных и несодержащие указателей.

492
18 ноября 2004 года
alibabaich
238 / / 08.07.2004
Цитата:
Originally posted by Green

Т.о. есть смысл подобным образом сохранять лишь простейшие структуры данных, т.е. содержащие только фундаментальные типы данных и несодержащие указателей.


А не простейшие?

501
18 ноября 2004 года
hell_admin
110 / / 02.10.2004
Цитата:
Originally posted by alibabaich

#pragma pack(1)
struct A
{
};
#pragma pack()


Вопрос про стандарт снимается..

А томозить оно не будет при выполнении
если так выравнивать ??? Если да то сильно или нет?

10
18 ноября 2004 года
Freeman
3.2K / / 06.03.2004
Цитата:
Originally posted by hell_admin
А томозить оно не будет при выполнении
если так выравнивать ??? Если да то сильно или нет?


По идее, тормозить должно, не просто же так используют выравнивание. Но вот визуально разницу в несколько или даже несколько десятков тактов процессора ты вряд ли заметишь.

3
18 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by alibabaich

А не простейшие?


Надо писать/использовать сериализацию

1.9K
18 ноября 2004 года
solovey
113 / / 25.07.2004
Цитата:
Originally posted by pavor

Спорим на 5 баков?


Я имел ввиду, что он не получит ожидаемого результата:)

527
18 ноября 2004 года
pavor
275 / / 28.09.2003
Цитата:
Originally posted by Green


Что бы это значило "границы данных"?

Указатели на vtbl находятся в начале экземпляра класса (и в начале каждой части экземпляра класса потомка для множественного наследования).
 
Код:
struct A
{
    int data;
    virtual void func() {}
};

A str;
A* pA = &str;

pA будет указывать не на данные (int data), а на vfptr (указатель на vtbl), а размер класса sizeof(A)=8: sizeof(vfptr) + sizeof(data).

Т.о.
fwrite((char*)&str, sizeof(str), 1, f);
запишет 8 байт информации, первые 4 из которых - vfptr

Так что ты имел в виду своей фразой про "границы данных"?! :}


В данном случае границы данных будут от 4 до 8 байта :)
В любом случае на мой взгляд определять в теле структуры указатели на виртуальные функции неудобно. Лучше в структуре объявить данные, а затем унаследовать от нее класс. Насколько я помню данные из базового класса располагаются сначала.
Насчет оператора char *, если даже его добавить, в приведенном коде он не сработает. Так как он должен быть применен к объекту класса, а не к адресу объекта.

1.9K
19 ноября 2004 года
solovey
113 / / 25.07.2004
Цитата:
Originally posted by pavor

В данном случае границы данных будут от 4 до 8 байта :)
В любом случае на мой взгляд определять в теле структуры указатели на виртуальные функции неудобно. Лучше в структуре объявить данные, а затем унаследовать от нее класс. Насколько я помню данные из базового класса располагаются сначала.
Насчет оператора char *, если даже его добавить, в приведенном коде он не сработает. Так как он должен быть применен к объекту класса, а не к адресу объекта.


fwrite((char*)str, sizeof(str), 1, f);?
так?

527
19 ноября 2004 года
pavor
275 / / 28.09.2003
Цитата:
Originally posted by solovey

fwrite((char*)str, sizeof(str), 1, f);?
так?


Да!

3
19 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by pavor

В любом случае на мой взгляд определять в теле структуры указатели на виртуальные функции неудобно. Лучше в структуре объявить данные, а затем унаследовать от нее класс. Насколько я помню данные из базового класса располагаются сначала.


Все зависит от порядка указания базовых классов и реализации компилятора.
В стандарте это не оговорено, поэтому "на свой страх и риск".

P.S. В VC++ v6 и v7 порядок следования такой.

4.5K
20 ноября 2004 года
NightSleeper
43 / / 09.10.2004
2 Green

Удачное совпадение, меня как раз интересует сохранение структуры в файл, и в частности приведение к char * в этом примере - что можно сказать о риске нарушения типовой безопасности? Похоже тут обойти приведение к char* не удастся, а если нужно записать значение типа int, то придется еще и reinterpret_cast использовать, т.е. без риска не получится?
527
20 ноября 2004 года
pavor
275 / / 28.09.2003
Цитата:
Originally posted by Green

Все зависит от порядка указания базовых классов и реализации компилятора.
В стандарте это не оговорено, поэтому "на свой страх и риск".

P.S. В VC++ v6 и v7 порядок следования такой.


Зато стандартом гарантируется, что работает TBase *pBase = reinterpret_cast(или static_cast)<Derived*>(pDerived);
А учитывая, что pBase - указатель на структуру, будет работать
fwrite((char*)pBase, sizeof(Base), 1, file);

3
23 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by NightSleeper
2 Green
Удачное совпадение, меня как раз интересует сохранение структуры в файл, и в частности приведение к char * в этом примере - что можно сказать о риске нарушения типовой безопасности? Похоже тут обойти приведение к char* не удастся, а если нужно записать значение типа int, то придется еще и reinterpret_cast использовать, т.е. без риска не получится?



Если в структуре лишь фундаментальные типы и массивы элементов таких типов, а так же агрегируются такие же структуры, имеющие только фундаментальные типы, то можно воспользоваться методом, который привел pavor, т.е. данные хранить отдельной структурой, а метода реализовывать лишь в наследнике, при этом при сохранении приводить к базовой структуре данных.

В вопросе топика указывается именно такая "простая" структура. На всякий пожарный надо бы из неё методы выкинуть и можно сохранять as is.

Но горе тому, кто применит такой метод к сложным структурам, агрегирующим разные классы. :devil:
Аминь.

4.5K
23 ноября 2004 года
NightSleeper
43 / / 09.10.2004
Цитата:
Originally posted by Green

Но горе тому, кто применит такой метод к сложным структурам, агрегирующим разные классы. :devil:
Аминь.



Да будет так! :)
Меня интересовало сохранение структуры без методов, т.е. просто поля.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог