Информативный заголовок: выделение памяти в C++
Пользователи, просматривающие топик: none
|
Зашли как: Guest
|
Имя |
Сообщение |
<< Старые топики Новые топики >> |
|
|
Информативный заголовок: выделение памяти в C++ - 2009-04-30 04:37:15.090000
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
задачка из области фокусов: ловкость рук и никакой магии c.cpp:
...
void C::size()
{
std::cout << "sizeof *this = " << sizeof(*this) << std::endl;
std::cout << "located from " << this << " to " << (this + 1) << std::endl;
}
...
main.cpp:
int main()
{
C obj;
std::cout << "sizeof obj = " << sizeof(obj) << std::endl;
std::cout << "located from " << &obj << " to " << (&obj + 1) << std::endl;
obj.size();
return 0;
}
вывод: sizeof obj = 4 located from 0xbfb66eac to 0xbfb66ebc sizeof *this = 8 located from 0xbfb66eac to 0xbfb66eec вот так - несложным, в принципе, фокусом ломается система выделения памяти в C++: в данном случае для объекта размером в 8 байт было выделено 4 байта памяти, во время свёртки стека произойдёт ошибка сегментации вопрос на подумать: как этого добиться? пряник и всеобщее признание тому, кто сможет получить подобный результат (различие во внешнем и внутреннем sizeof для объекта). дополнительный пряник тому, кто объяснит причину возникновения ошибки лезьть в compiler internals запрещено, весь код должен быть в рамках ISO C++. описанный выше трюк одинаково хорошо работает с GCC и MSVS, не зависит от системы; может разрушить как стек, так и кучу. архитектура пусть будет фиксированная, x86. знание ассемблера для решения является крайне полезным, но не обязательным N.B. существует по крайней мере два умеренно законных метода получить такое поведение компилятора
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 10:24:41.846666
|
|
|
rgo
Сообщений: 7170
Оценки: 281
Присоединился: 2004-09-25 05:14:25
|
причину я не объясню, но могу предположить. Все эти классы/структуры C++ помимо объявленных в них полей содержат всякую управляющую информацию, типа указателя на таблицу виртуальных функций. Причём никто не гарантирует, что &obj будет указывать на начало области выделенной под объект. Тот же указатель на vft может иметь адрес ((void**)&obj)[-1]. Что такое sizeof в C++, я честно говоря не знаю. Я читал стандарты про C – там всё прозрачно и соответствует интуиции. В C++ я боюсь в таких вещах полагаться на интуицию. Но если sizeof – это размер который занимает структура хранящая члены-переменные, а obj.size() – это размер выделенный из кучи, то это вполне всё объяснит. И мне кажется, что если хочется знать верный ответ на поставленный вопрос, то рыть надо именно в эту сторону. ps. вот это:std::cout << "located from " << &obj << " to " << (&obj + sizeof(obj)) << std::endl; Бред. Надо так:std::cout << "located from " << &obj << " to " << (&obj + 1) << std::endl;
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 11:50:38.473333
|
|
|
Dgedit
Сообщений: 131
Оценки: 0
Присоединился: 2007-02-04 15:07:37.163333
|
Как вставит тут скрин? У меня ничего такого нету - все работает так как должно. И то что rgo сказал не влияет я пробовал и с виртуальными функциями и без них. Я компилировал в Visual Studio.
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 12:20:18.766666
|
|
|
SmanxX1
Сообщений: 208
Оценки: 0
Присоединился: 2007-07-31 14:33:56.650000
|
Denaturat Залей куда-нибудь бинарник этой программки. П.С. Вот для такого:
class C {
public:
void size() {
printf("sizeof *this = %#2.2x\n",sizeof(*this));
printf("located from %#2.2x to %#2.2x\n", this, (this + sizeof(*this)));
};
};
int main()
{
C obj;
printf("sizeof obj = %#2.2x\n",sizeof(obj));
printf("located from %#2.2x to %#2.2x\n",&obj,(&obj + sizeof(obj)));
obj.size();
return 0;
}
Результат:
sizeof obj = 0x01
located from 0x12ff7b to 0x12ff7c
sizeof *this = 0x01
located from 0x12ff7b to 0x12ff7c
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 14:49:26.233333
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: rgo Что такое sizeof в C++, я честно говоря не знаю. Я читал стандарты про C – там всё прозрачно и соответствует интуиции. В C++ я боюсь в таких вещах полагаться на интуицию. Но если sizeof – это размер который занимает структура хранящая члены-переменные, а obj.size() – это размер выделенный из кучи, то это вполне всё объяснит. И мне кажется, что если хочется знать верный ответ на поставленный вопрос, то рыть надо именно в эту сторону. и внутри и снаружи применяется один и тот же sizeof. каким бы он ни был, он один и тот же. а вот понять, как он работает в C++ - это существенно quote:
ORIGINAL: rgo ps. вот это:std::cout << "located from " << &obj << " to " << (&obj + sizeof(obj)) << std::endl; Бред. Надо так:std::cout << "located from " << &obj << " to " << (&obj + 1) << std::endl; спасибо, опечатался. в варианте с единицей потерянные 4 байта хорошо видно: sizeof obj = 4 located from 0xbffe5b3c to 0xbffe5b40 sizeof *this = 8 located from 0xbffe5b3c to 0xbffe5b44
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 14:50:26.370000
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: Dgedit У меня ничего такого нету - все работает так как должно. И то что rgo сказал не влияет я пробовал и с виртуальными функциями и без них. Я компилировал в Visual Studio. так как должно каждый может :) задача именно в том, чтобы получить не как должно
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 14:54:33.243333
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: SmanxX1 Denaturat Залей куда-нибудь бинарник этой программки. только если без него никто не решит quote:
ORIGINAL: SmanxX1 П.С. Вот для такого… ну вроде бы не секрет, что выделение памяти в C++ обычно работает как положено. так что я не совсем понимаю, что ты хотел этим кодом сказать ещё раз. задача - поломать этот механизм, получить средствами чистого ISO C++ нарисованный выше результат
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 16:40:37.213333
|
|
|
Dgedit
Сообщений: 131
Оценки: 0
Присоединился: 2007-02-04 15:07:37.163333
|
Ты тогда объясняй понятнее. Получается мы имеем черный ящик в виде объекта А. надо описать этот черный ящик так чтобы получить результат который ты вывел в примере?
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 17:08:23.900000
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: Dgedit Ты тогда объясняй понятнее. Получается мы имеем черный ящик в виде объекта А. надо описать этот черный ящик так чтобы получить результат который ты вывел в примере? бинго!
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 17:30:25.993333
|
|
|
_SaZ_
Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
|
Ещё не все потеряно :D. Не копался, но имхо дело с vtable / наличием абстрактных методов.
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 17:54:22.090000
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: _SaZ_ дело с vtable / наличием абстрактных методов. ну тогда вопрос тебе лично: где расположен vtable в памяти?
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 18:49:55.333333
|
|
|
Dgedit
Сообщений: 131
Оценки: 0
Присоединился: 2007-02-04 15:07:37.163333
|
Адрес vtaable расположен в первых четырех байтах полиморфного объекта.
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 19:30:23.840000
|
|
|
SmanxX1
Сообщений: 208
Оценки: 0
Присоединился: 2007-07-31 14:33:56.650000
|
quote:
ещё раз. задача - поломать этот механизм, получить средствами чистого ISO C++ нарисованный выше результат Ну так бы сразу и написал, а то quote:
вот так - несложным, в принципе, фокусом ломается система выделения памяти в C++ понимается, как будто это и есть уже готовый код, где действительно какая-то черная магия. По задаче. Нуу, ошибку сегментации можно получить разными способами, например разыменованием нулевого указателя. Может как-нибудь с this поиграться, только вряд ли это даст нужный результат.
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 19:33:00.326666
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: SmanxX1 По задаче. Нуу, ошибку сегментации можно получить разными способами, например разыменованием нулевого указателя. я чёрным по серому в постановке задачи написал откуда получается ошибка сегментации. никаких нулевых указателей, просто неверно выделенная память на стеке quote:
ORIGINAL: SmanxX1 Может как-нибудь с this поиграться, только вряд ли это даст нужный результат. попробуй
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 19:35:29.660000
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: Dgedit Адрес vtaable расположен в первых четырех байтах к задаче это не относится, но вот в этой фразе есть ошибка. выделенное - всегда ли?
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 20:01:21.736666
|
|
|
Dgedit
Сообщений: 131
Оценки: 0
Присоединился: 2007-02-04 15:07:37.163333
|
Ну я не встречал нигде описания случаев когд аэто может быть по другому. Возможно что в стандарте можно что-то такое выкопать необычное когда виртуальнаая таблица будет не в первых 4 байтах. Если бывает так как ты говоришь то напиши пожалуйста будет интересно расширить кругозор
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 20:15:36.500000
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
какой размер указателя на 16, 32 и 64-битных архитектурах?
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 20:21:56.666666
|
|
|
SmanxX1
Сообщений: 208
Оценки: 0
Присоединился: 2007-07-31 14:33:56.650000
|
-del (не то)
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 20:28:09.776666
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
del :)
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 22:22:25.770000
|
|
|
kreol
Сообщений: 823
Оценки: 0
Присоединился: 2007-03-08 03:13:06.876666
|
Возможно, нужно рыть в сторону вот этих особенностей: quote:
When the sizeof operator is applied to a class, struct, or union type, the result is the number of bytes in an object of that type, plus any padding added to align members on word boundaries. The result does not necessarily correspond to the size calculated by adding the storage requirements of the individual members. quote:
If an unsized array is the last element of a structure, the sizeof operator returns the size of the structure without the array. Хотя я больше склоняюсь к версии с vtable. В любом случае это нужно читать про выделение памяти для объектов и смотреть на смещения.
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-04-30 22:35:54.236666
|
|
|
kreol
Сообщений: 823
Оценки: 0
Присоединился: 2007-03-08 03:13:06.876666
|
А ещё стоит обратить внимание на то, что sizeof - это оператор времени компиляции. Может быть, во время компиляции класса его размер другой, нежели во время компиляции модуля, где объявляется объект данного класса? Но это уже нужно знать С++ лучше, чем его знаю я :)
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-05-01 00:38:58.096666
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: kreol …во время компиляции класса его размер другой, нежели во время компиляции модуля, где объявляется объект данного класса? совершенно верно, вообще говоря. осталось это реализовать
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-05-04 12:57:34.303333
|
|
|
rgo
Сообщений: 7170
Оценки: 281
Присоединился: 2004-09-25 05:14:25
|
что я делаю не так:[~]$ cat tmp.cc
#include <iostream>
class C
{
public:
C (int n=0) : n (n) {}
void size ();
private:
int n;
};
void C::size()
{
std::cout << "sizeof *this = " << sizeof(*this) << std::endl;
std::cout << "located from " << this << " to " << (this + 1) << std::endl;
}
int main ()
{
C obj;
std::cout << "sizeof obj = " << sizeof(obj) << std::endl;
std::cout << "located from " << &obj << " to " << (&obj + 1) << std::endl;
obj.size();
return 0;
}
[~]$ g++ tmp.cc
[~]$ ./a.out
sizeof obj = 4
located from 0xbf91b83c to 0xbf91b840
sizeof *this = 4
located from 0xbf91b83c to 0xbf91b840
[~]$ +++ попробовал разбить это на два файла, и потом линковать объектники… результаты отличаются цифрами, но "чёрного ящика" я не вижу… ps. ах да. gcc версии 4.1.2 pps. на домашнем компьютере, то же самое, с точностью до незначительных деталей:[rgo tmp]$ ./a.out
sizeof obj = 4
located from 0x7fff8f5f1630 to 0x7fff8f5f1634
sizeof *this = 4
located from 0x7fff8f5f1630 to 0x7fff8f5f1634
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-05-04 16:37:06.230000
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
quote:
ORIGINAL: rgo что я делаю не так ты всё делаешь правильно - как и предполагают компилятор/линкер,- потому и результат вполне ожидаемый для того, чтобы получить описанную выше ошибку, их надо обмануть. для этого достаточно добавить одну строчку и один файл, либо строчек пять-шесть в существующих файлах
|
|
|
RE: Информативный заголовок: выделение памяти в C++ - 2009-05-07 15:41:58.580000
|
|
|
Denaturat
Сообщений: 1741
Оценки: 453
Присоединился: 2008-10-27 20:50:06.380000
|
скучно как-то. идеи закончились?
|
|
|
|
|