Размещение структур в памяти
struct A
{
char s[256];
void somefunc();
char s2[1024];
... // другие функции
}
При записи структуры в файл:
A str;
...
FILE* f = fopen("file", "wb");
fwrite((char*)&str, sizeof(str), 1, f);
..
Ну и загрузке в обратном порядке:
Т.е. простыми словами что запишется в файл, только члены-переменные или еще чего-то от функций ???
Вопрос может показаться глупым, но никогда до этого не сталкивался с записью структур или классов с членами-функциями в файл, вот и интерестно как отработает такой код:
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'ы будут содержать в себе мусор.
Вопрос может показаться глупым, но никогда до этого не сталкивался с записью структур или классов с членами-функциями в файл, вот и интерестно как отработает такой код:
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)
{
/* твой код */
}
От функций ничего не запишется. Запишутся только значения переменных.
Ну почему же...
Запишутся указатели на виртуальные таблицы и пр. служебная информация.
Ну почему же...
Запишутся указатели на виртуальные таблицы и пр. служебная информация.
Запишутся только если он выйдет за границы данных.
ниче он незапишет, т.к. ты не определил оператор (char*)
Спорим на 5 баков?
Спорим на 5 баков?
Мне Процент, Я же тему начал :D, хотя мне ладно мне хватит просто окончательного ответа запишет ли чего или нет, например всякие там vtbl.
Мне Процент, Я же тему начал :D, хотя мне ладно мне хватит просто окончательного ответа запишет ли чего или нет, например всякие там vtbl.
Ты пробовал провести эксперимент? Не обязательно записывать в файл данные. Достаточно просто посчитать размер предполагаемый и сравнить его с возвращаемым sizeof. Если данные выровнены на 4 байта, то гарантированно при совпадении размеров совпадут и данные.
Ты пробовал провести эксперимент? Не обязательно записывать в файл данные. Достаточно просто посчитать размер предполагаемый и сравнить его с возвращаемым sizeof. Если данные выровнены на 4 байта, то гарантированно при совпадении размеров совпадут и данные.
Я уже попробывалб размеры вроде совпадают, интерестно что про это говорит стандарт?
И как сделать что бы не зависело от выравнивания компилятора?
Запишутся только если он выйдет за границы данных.
Что бы это значило "границы данных"?
Указатели на vtbl находятся в начале экземпляра класса (и в начале каждой части экземпляра класса потомка для множественного наследования).
{
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
Так что ты имел в виду своей фразой про "границы данных"?! :}
Я уже попробывалб размеры вроде совпадают, интерестно что про это говорит стандарт?
Про что ты хочешь узнать из стандарта?
Сформулируй вопрос, плз.
И как сделать что бы не зависело от выравнивания компилятора?
#pragma pack(1)
struct A
{
};
#pragma pack()
Вот только сохранение таким способом, как ты пытаешься сделать неверное. Оно приведет к ошибкам, точнее к потере информации в первую очередь, если:
1) класс содержит указатели, т.к. они станут невалидными при повторном запуске приложения;
2) класс содержит виртуальные методы или порожден от классов, содержащих виртуальные методы;
3) класс агрегирует другие сложные классы (под сложными будем понимать классы которые могут соотв. этим перечисленным условиям).
Т.о. есть смысл подобным образом сохранять лишь простейшие структуры данных, т.е. содержащие только фундаментальные типы данных и несодержащие указателей.
Т.о. есть смысл подобным образом сохранять лишь простейшие структуры данных, т.е. содержащие только фундаментальные типы данных и несодержащие указателей.
А не простейшие?
#pragma pack(1)
struct A
{
};
#pragma pack()
Вопрос про стандарт снимается..
А томозить оно не будет при выполнении
если так выравнивать ??? Если да то сильно или нет?
А томозить оно не будет при выполнении
если так выравнивать ??? Если да то сильно или нет?
По идее, тормозить должно, не просто же так используют выравнивание. Но вот визуально разницу в несколько или даже несколько десятков тактов процессора ты вряд ли заметишь.
А не простейшие?
Надо писать/использовать сериализацию
Спорим на 5 баков?
Я имел ввиду, что он не получит ожидаемого результата:)
Что бы это значило "границы данных"?
Указатели на vtbl находятся в начале экземпляра класса (и в начале каждой части экземпляра класса потомка для множественного наследования).
{
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 *, если даже его добавить, в приведенном коде он не сработает. Так как он должен быть применен к объекту класса, а не к адресу объекта.
В данном случае границы данных будут от 4 до 8 байта :)
В любом случае на мой взгляд определять в теле структуры указатели на виртуальные функции неудобно. Лучше в структуре объявить данные, а затем унаследовать от нее класс. Насколько я помню данные из базового класса располагаются сначала.
Насчет оператора char *, если даже его добавить, в приведенном коде он не сработает. Так как он должен быть применен к объекту класса, а не к адресу объекта.
fwrite((char*)str, sizeof(str), 1, f);?
так?
fwrite((char*)str, sizeof(str), 1, f);?
так?
Да!
В любом случае на мой взгляд определять в теле структуры указатели на виртуальные функции неудобно. Лучше в структуре объявить данные, а затем унаследовать от нее класс. Насколько я помню данные из базового класса располагаются сначала.
Все зависит от порядка указания базовых классов и реализации компилятора.
В стандарте это не оговорено, поэтому "на свой страх и риск".
P.S. В VC++ v6 и v7 порядок следования такой.
Удачное совпадение, меня как раз интересует сохранение структуры в файл, и в частности приведение к char * в этом примере - что можно сказать о риске нарушения типовой безопасности? Похоже тут обойти приведение к char* не удастся, а если нужно записать значение типа int, то придется еще и reinterpret_cast использовать, т.е. без риска не получится?
Все зависит от порядка указания базовых классов и реализации компилятора.
В стандарте это не оговорено, поэтому "на свой страх и риск".
P.S. В VC++ v6 и v7 порядок следования такой.
Зато стандартом гарантируется, что работает TBase *pBase = reinterpret_cast(или static_cast)<Derived*>(pDerived);
А учитывая, что pBase - указатель на структуру, будет работать
fwrite((char*)pBase, sizeof(Base), 1, file);
2 Green
Удачное совпадение, меня как раз интересует сохранение структуры в файл, и в частности приведение к char * в этом примере - что можно сказать о риске нарушения типовой безопасности? Похоже тут обойти приведение к char* не удастся, а если нужно записать значение типа int, то придется еще и reinterpret_cast использовать, т.е. без риска не получится?
Если в структуре лишь фундаментальные типы и массивы элементов таких типов, а так же агрегируются такие же структуры, имеющие только фундаментальные типы, то можно воспользоваться методом, который привел pavor, т.е. данные хранить отдельной структурой, а метода реализовывать лишь в наследнике, при этом при сохранении приводить к базовой структуре данных.
В вопросе топика указывается именно такая "простая" структура. На всякий пожарный надо бы из неё методы выкинуть и можно сохранять as is.
Но горе тому, кто применит такой метод к сложным структурам, агрегирующим разные классы. :devil:
Аминь.
Но горе тому, кто применит такой метод к сложным структурам, агрегирующим разные классы. :devil:
Аминь.
Да будет так! :)
Меня интересовало сохранение структуры без методов, т.е. просто поля.