быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
|
|||||||||||
1 | |||||||||||
Почему глобальный объект, объявленный до main, конструируется в ней?13.09.2011, 17:16. Показов 3600. Ответов 36
Метки нет (Все метки)
Всё просто, имеем код:
Так, открываем прогу в отладчике OllyDbg, стоим на точке входа (у всех своя, у меня) 401220, ставим бряк на 401290, на main, запускаем. Видим, что бряк сработал, но конструктор не вызвался! Чуть пониже в окне дизассембра видим вызов printf с аргументом "konstruktor", то есть объект конструируется в main. Как такое может быть? Компилятор g++. Спасибо, кто откликнется.
0
|
13.09.2011, 17:16 | |
Ответы с готовыми решениями:
36
Почему я не могу скрыть глобальный объект document? Почему в GUI нельзя использовать объект в main? Почему ругается на не объявленный идентификатор Глобальный объект |
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
|
|
13.09.2011, 18:56 [ТС] | 21 |
Я записал, На бумажку на всякий случай, чтобы не было недоразумений. Вот как вы сказали:
По моему первый оператор main и есть начало main. Не? Если не так, уточните понятия, как это сделал я. За printf: как бы не хотелось мне думать, что я просто "не заметил" вызова конструктороа, это не так. Брякаюсь на начало main (первый оператор или как его там), пошаговто трассирую и попадаю на printf с параметром "konstruktor". Так что увы и ах, объект создаётся в maine, что ставит с ног на голову мои и без того шаткие знания. Ребята, может в опциях компилятора надо что поправить? Я щас это смотрю уже.
0
|
13.09.2011, 19:18 | 22 |
Это не так. В начале процедуры main (с точки зрения бинарного кода и отладчика), как и в начале любой процедуры идёт так называемый пролог. Как правило это настройка стека, настройка указателей стека и прочих вещей, о которых пользователю знать незачем, потому как в языке программирования нет этих понятий (на то он и язык, чтобы не опускаться до уровня системы команд, программных соглашений и т.п.)
Какие именно понятия? Что такое "первый оператор main'а"? В твоём случае это printf (который внутри main'а). Ты уж определись, на начало main (низкоуровневое понятие) или на первый оператор main (высокоуровневое понятие) Внимательно читай пост #9. А ещё лучше, покажи дизассемблер своей программы Добавлено через 1 минуту Т.е. пост #4
0
|
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
|
||||||
13.09.2011, 19:35 [ТС] | 23 | |||||
Всё понятно.
Значит, ещё раз. Чтобы куда-то брякнуться, мне надо цифры какие-то. Адрес то есть. Я его получаю так:
Потом эту прогу открываю в отладчике и ставлю бряк на 401290, думая, что это начало main (естессно, ошибочно, ибо я всегда думаю ошибочно) Ваш вариант нахождения адреса для бряка обрисуйте пожалуйста. (Только пожалуйста не "первый оператор", а то мы с вами так далеко не уйдём.) Добавлено через 1 минуту ...Кстати, пост номер 9 на корню зарубает мою тягу к знаниям.
0
|
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
|
|
13.09.2011, 19:43 | 24 |
Результаты экспериментов.
Откопал MinGW 3.4.5 и GDB 6.8 В этой связке у меня работает не так, как у ТС. Если установить breakpoint на имя main или на адрес, который выводится потом в printf (это 2 разных места) то в любом случае к моменту остановки слово konstruktor уже выведено. Если смотреть ассемблерный код, то внутри функции main можно увидеть вызов функции __main. Функция __main проверяет, вызывалась ли она уже, и если нет, то вызывает конструкторы глобальных объектов (функция __do_global_ctors). Так что формально, вызов конструкторов возможен уже после входа в main. Но. Первый раз функция __main вызывается на этапе инициализации из функции __mingw_CRTStartup, ещё до вызова функции main Так что в моей версии конструкторы вызываются до main, как и должно быть. Но программисту все эти тонкости всё-равно ни к чему, если всё работает как надо. Кстати, MinGW 4.5.2 строит код точно так же, а вот в Linux/x86_64 GCC 4.5.1 никаких посторонних вызовов внутри функции main не обнаружено.
0
|
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
|
|
13.09.2011, 19:58 [ТС] | 25 |
У меня 3.4.2, можешь скинуть куда-нибудь?
Добавлено через 3 минуты Хотя... как понять брейкпонт на имя? Тебе отладчик подсказывает, где находится имя?
0
|
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
|
|
13.09.2011, 20:00 | 26 |
Кого скинут? 3.4.5, на котором я экспериментировал, входит в стостав wxDev-C++.
Версия 4.5.2 с sourceforge, кажется. У niXman в подписи можно найти 4.6.1 с бустом. GDB без оболочек является консольным отладчиком. Командами управляется. То есть я имел в виду команду Код
break main
0
|
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
|
|||||||||||
13.09.2011, 20:20 [ТС] | 27 | ||||||||||
А с этим как быть?
============================================ А точнее если: что же тогда выводится по
Добавлено через 11 минут Час от часу не легче, оказывается, на main нельзя брать адрес: http://msdn.microsoft.com/ru-r... adt5z.aspx Cannot have its address taken. Но тогда это кое-что проясняет (хотя g++ отношение к мелкомягким не имеет, но тем не менее), а именно: адрес main, полученный программным путём- фуфловый. Значит, может быть действительно, брякаться надо на
0
|
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
|
|
13.09.2011, 20:40 | 28 |
Да, об этом я уже сказал, но это не выдумка Microsoft, это описано в стандарте C++. Впрочем, к GCC это не относится, он разрешает получение адреса и рекурсивный вызов main().
В случае VisualStudio компилятор просто не позволит получить адрес. В случае GCC адрес самый что ни на есть настоящий — начало кода функции main(). Как я уже говорил, я ставил breakpoint и по символическому имени, и по машинному адресу начала main. В обоих случаях конструктор уже был вызван. Добавлено через 5 минут Собственно, разница между этими точками останова только в том, что по символическому имени пропускается настройка стека.
0
|
13.09.2011, 21:01 | 29 |
Единственный человеческий способ остановиться в правильной точке - это скомпилировать с отладочной информацией и установить брекпоинт в виде "break main" или "break t.c:14" (я так понимаю, что у тебя отладчик gdb). Другого не дано.
Нечеловеческий способ - это продизассемблировать программу и глазками посмотреть адрес, который будет соответствовать первому оператору (если понимаешь в ассемблере). В режиме с оптимизациями ты этого в принципе уже получить точным образом, потому как компилятор скорее всего коды перемешает и не факт, что в программе найдётся точная граница между тем, как "первый оператор уже выполнен" и "первый оператор ещё не выполнен", потому что это на языке только один оператор, а в коде это будет несколько машинных инструкций, которые могут перемешаться с инструкциями другого оператора
0
|
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
|
|
13.09.2011, 21:13 | 30 |
Так вроде ж OllyDbg у него. Фиг его знает, как там с интеграцией с кодом от MinGW. Это я GDB мучил.
0
|
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
|
|
13.09.2011, 21:27 | 31 |
Раньше, помнится, и борландовские компиляторы разрешали. Баловался сам. Удобно параметры командной строки обрабатывать без цикла - рекурсивным вызовом.
0
|
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
|
|
13.09.2011, 21:29 [ТС] | 32 |
Там ничё сложного. Но я предпочёл всё же получить адрес для бряка программно. А вы мне опять первый оператор да первый оператор
...Вообще сказка про белого бычка. Чтобы знать первый оператор функции надо знать где эта функция начинется чтобы посмотреть её первый оператор чтобы посмотреть где она начинается чтобы... Короче, вы не знаете.
0
|
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
|
|
13.09.2011, 21:39 | 33 |
1
|
13.09.2011, 21:55 | 34 |
Я тебе уже объяснял, что адрес функции - это совсем не то. От точки входа в main до printf'а может чёрт-те сколько команд исполниться.
Читай пост #29, там всё написано. Если не умеешь работать с ассемблером и не имеешь представления о том, как работает компилятор, то попросту не стоит лазить в отладчике на низком уровне (без отладочной информации). Объект вообще создаётся compile-time. А то, о чём ты говоришь, называется "инициализируется". Может статья тебе поможет, но там много букв Конструкторы и деструкторы Добавлено через 11 минут И ещё::
0
|
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
|
|
13.09.2011, 22:49 [ТС] | 35 |
Да не. Ничё не даст. Опять тягомотину на пустом месте разводить будешь.
Добавлено через 13 минут Короче, и смех и грех. Качнул mingw-get-inst-20100831.exe, так вроде нормально всё, сперва создаёт объекты, потом вызывает main, как и задумано. Так ведь он добавляет в код моей проги загрузку вот этой библиотеки: libgcc_s_dw2-1.dll; он с собой приволок её из интернета. Приходится кидать libgcc_s_dw2-1.dll в одну папку с исходником и наблюдать как предсказуемо работает моя прога, удовольствие малоприятное. Так Этот компилятор что, для всех прог будет требовать наличие libgcc_s_dw2-1.dll? ужасно так-то. Добавлено через 32 минуты grizlik78, спасибо,тебе, дружище! Может теперь буду почаще менять компиляторы, а то у меня аж с 2004-го года стоял. Поковырялся в переменных среды и всё заработало. Так что спишем всё на старость моего компилятора. Щас поставил 4.5.0. До свидания, друзья. До новых встреч!
0
|
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
|
|
13.09.2011, 22:53 | 36 |
kravam, писать программы, поведение которых зависит от компилятора - зло
0
|
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
|
|
13.09.2011, 22:59 [ТС] | 37 |
Да не, поведение не зависело, вы невнимательно читали тему или вообще не читали её. Просто я мысля обнаружил расхождение между теорией и практикой и решил его решить.
0
|
13.09.2011, 22:59 | |
13.09.2011, 22:59 | |
Помогаю со студенческими работами здесь
37
Глобальный объект Глобальный объект Глобальный объект Глобальный объект Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |