Операция new с размещением
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Доброго времени суток всем!
Есть такой код, в котором используется статический массив в качестве буфера памяти для размещения в нем массива структур.
Вывод программы такой:
Вопрос:
Если размер буфера 1 байт то куда размещается массив структур
matrix
размером в 48 байт?Ответ:
Массив структур
matrix
размером в 48 байт никуда не размещается. В этом операторе:выделения памяти не происходит (см. третью форму new). Перед эти оператором память должна быть уже выделена в
buffer
.Далее — цепь счастливых случайностей: (1) ты не пишешь в структуры, которые были «выделены» в
buffer
; (2) ты переводишь указательpchaff
на другой адрес, из которого и читаешь информацию (pchaff = matrix
— теперьpchaff
кbuffer
уже не имеет никакого отношения).А вот в таком виде твоя программа будет работать уже «странно»:
поскольку при присваивании значений полям структуры ты будешь изменять значение переменной
test
.Череп, вот вывод твоего варианта программы у меня в системе
Значения переменной тест не изменились. ???
Но смысл я понял. Нужно сначала выделить память, а потом работать с указателем. Переписал я программу по другому:
И получил такой результат:
То есть, значение на которое указывает указатель
pchaff
находиться по адресу по которому находиться массивbuffer
, но размер буфера == 1, размер указателя == 4, а размер значения на который указывает указатель (в данном случае первый элемент массива структур) == 24.Вопрос: все-таки как это уместилось в одном байте??? В чем проблема? :)))
PS Кстати, копирование строковых литералов, в массив
char dross[20]
— это единственный способ инициализации массива в данной ситуации?А если перед
cout << test
добавить строкуТо какой вывод будет?
Вот такой:
адреса разные.
Ничего не пойму. :(((
В первом коде я дал промашку. Но что же происходит во втором (переписанном) коде? Я же попал по адресу :)
Череп, объясняй, а то я уже начинаю думать, что операция
new
с размещением самая чудесная операция С++.Я тут уже задумал S.T.A.L.K.E.Rа упаковать до 20 байт :)))
Получается вот что.
Здесь ты резервируешь буфер в 1 байт. На самом деле компилятор (видимо по соображениям выравнивания) выделяет 32 байта. Точнее говоря, выделяет 1 байт, а ещё 31 — «отходы производства» — не используются.
Если следом за этим дописываем
то получаем, что адрес начала
buffer
— 0x106916a, а адрес началаtest
— 0x1069138 (разность адресов — 32 байта).Теперь ты делаешь
Операция
new
по адресуbuffer
создаёт первый объект типаchaff
(вызывает конструктор структуры без аргументов, сгенерированный автоматически, который, естественно, ничего не делает), затем по адресуbuffer+24
таким же образом создаёт второй объект типаchaff
. Получается следующая картина:т.е. первый
chaff
«успешно» умещается в отведённые компилятором подbuffer
32 байта, а второйchaff
уже залезает на массивtest
. Что я тебе и пытался продемонстрировать.Так что фокус с упаковкой в 20 байт не получится )) Ты просто работаешь с памятью, которая тебе не принадлежит.
Вот ещё одна вариация «на тему»
У меня выдаёт
Обрати внимание на адреса, которые выводит конструктор, и адреса
buffer
иtest
. И сравни со схемкой размещения переменных в памяти (см. выше).Если в этой программке
DROSSSIZE
установить в 2048, то у меня программа завершается аварийно.Компилятор: TDM-GCC 4.8.1 32-bit Debug
Спасибо, Череп, за комментарии.
В общем я «разобрал» свой компилятор почти на части. Добрался до функций и переменных которыми оперирует компилятор при выделении памяти (ОЧЕНЬ МНОГО ВСЕГО НЕ ПОНЯТНОГО, но обо всем по порядку).
Учитывая твои комментарии пришел к выводу, что при использовании операции
new
с размещением контроль за переполнением буфера полностью лежит на программисте.Исходя из этого, решил написать все, как говорится, «красиво». Под создание массива из двух структур размером 48 байт, выделил под буфер 50 байт (кстати, компилятор внутренне действительно выделяет памяти больше чем запрашивается, в данном случае 86 байт) и получилось, на мой взгляд, все просто, лаконично и понятно. Выделил, разместил и ...
и получил такой вывод, который меня снова поставил в тупик.
Адрес и размер структуры
pchaff[0]
,а адрес структуры
pchaff[1]
на 18 байт больше.
Вопрос 1: Что за магия? Что я упускаю и не могу понять?
Решил продублировать себя с помощью динамически выделенного массива под буфер (из соображения, что компилятор пресечет все попытки чтения памяти за пределами массива
buffer
). Мои надежды оправдались, компилятор действительно стал «ругаться» если я устанавливал значениеBUFFSIZE
меньше чем внутренне выделяется компилятором.Но написав такой код, снова натыкаюсь на те же грабли, что и в первом примере.
Вывод такой
Снова те же грабли только в профиль.
Вопрос 2: См. вопрос 1 :))) (What's hell of this? Sorry.)
Череп, объясни для тех кто на бронепоезде ))) За ранее спасибо.
Ответ 1. Отдыхать вам, батенька, больше надо ))
И считать в единой системе счисления.
0x0108A150 - 0x0108A138 = 0x18
, что в десятичной системе равно 24 байтам.Ответ 2. См. ответ 1 ))
Я, правда, не понял кто и на что у тебя стал ругаться. Компилятор? Ему вроде должно быть фиолетово. Или ты «получал» при выполнении программы? Т.е. от исполняющей системы (RTS — run-time system, она же CRT — C run-time) C++?
Хочется все ,вся и сразу охватить своим «умишкой», а на самом простом — грабли :((( Семен Семеныч!!! Эта операция
new
с размещением мне чуть «крышу» не сорвала :)))Спасибо, Череп!!!
1. Кстати, я тут между делом, вопрос задавал
Потому как компилятор «ругается» (выдает предупреждение)
Можно ли в таких ситуациях использовать в программе такое определение, как предлагает компилятор
дабы отключить вывод предупреждения?
2. И еще, я где-то тебя спрашивал, не найду, можно ли на одной ОС ставить два компилятора?
Ты говорил, что можно, только нужно соблюдать осторожность.
У меня установлена MS VS 2010. Если можно установить второй компилятор, то какой: Code::Blocks или DevC++? И какие осторожности нужно соблюдать?
Честно говоря я пытался поставить Dev так у меня все значки в проектах VS с расширением .h и .cpp стали отображаться как значки Dev. И пытался поставить Code::Blocks, при установке всплывает вопрос — Сделать компилятор TDM-GCC по умолчанию? Что это значит и какие после этого будут последствия хз?
Подскажи пожалуйста.
ЗАРАНЕЕ СПАСИБО!!! )))
Это, наверное, один из главных постулатов программирования!!!)))
Раз, два, три, четыре, пять начинаю отдыхать... ... ...
Массив типа
char
— он и есть обычный массив типаchar
. А какой-то особой «ситуации» я не вижу. Некий альтернативный способ я применил в примере в моём посте ранее.Хм... А ты понял, что тебе написал компилятор?
Вообще там написано, что функция
strcpy
небезопасна. И рекомендуют вместо неё использовать функциюstrcpy_s
. Далее «бла-бла» про то, как подавить вывод предупреждения.К твоим изысканиям по поводу
new
это сообщение не имеет никакого отношения.Я бы тебе рекомендовал использовать
strcpy_s
, а не давить предупреждения. (Вообще, давить предупреждения — плохая практика. Можно не заметить грабли гигантского размера.)Однако с safe-версиями некоторых функций есть одна неприятность: они не стандартизованы, т.е. в другом компиляторе их может не быть (например в MinGW gcc). Код становится непереносимым, если не предпринять некоторых мер. Но если ты однозначно работаешь с MS VC++, то на счёт переносимости можешь не заморачиваться.
На самом деле ты спрашиваешь «можно ли ставить несколько IDE?». Компилятор, обычно, это просто приложение с интерфейсом командной строки, которое не «встраивается» в систему. А вот IDE (интегрированная среда разработки) может перехватывать на себя, например, ассоциацию файлов (по расширению имён файлов) или встраивать в ОС свой отладчик (возможно с установкой драйверов, служб и пр.).
С расширениями имён файлов обычно всё достаточно просто. Можно всегда перенастроить либо средствами самой IDE, либо через возможности ОС. Расширение имени файла для файла проекта конкретной IDE обычно уникально и не требует перенастройки.
С интеграцией отладчиков в систему надо быть осторожнее. Иногда (редко) бывают конфликты. Да и лишние активные драйверы/службы в системе не нужны. Надо пробовать. Если что-то пойдёт не так — переустановить одну или обе IDE. При установке инсталлятор обычно задаёт вопрос об установке отладчика.
Конкретно по MinGW и MS VS: уживаются совершенно мирно. MinGW не интегрирует свой отладчик в систему.
Code::Blocks умеет использовать множество компиляторов, в частности и MinGW gcc, и MS VC++. Можно установить только IDE без компилятора (в комплекте может быть MinGW — смотри какой дистрибутив скачиваешь).
У меня, например, установлены MS VS, DevC++ и Code::Blocks. Причём последние две IDE используют один и тот же компилятор MinGW, который шёл в комплекте с DevC++. Сначала был поставлен MS VS, потом добавлен DevC++ с MinGW, потом поставил Code::Blocks без компилятора. Полёт нормальный.
По удобству пользования, IMHO, Code::Blocks получше, чем DevC++. Хотя и у DevC++ есть свои прелести. Но MS VS по удобству — сильно впереди, безо всяких IMHO, и по редактированию исходников, и по отладке.
Перенастроить ассоциацию файлов .h и .cpp на VS можно в VS: меню Сервис -> Параметры -> Среда -> Общие -> кнопка Управление сопоставлением расширений файлов.
Это оно для себя делает компилятор по умолчанию. Во вне IDE эта установка не распространяется.
ЧЕРЕП, СПАСИБО !!!