Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/18: Рейтинг темы: голосов - 18, средняя оценка - 5.00
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
1

Почему глобальный объект, объявленный до main, конструируется в ней?

13.09.2011, 17:16. Показов 3600. Ответов 36
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всё просто, имеем код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <windows.h>
#include <stdio.h>
using namespace std;
 
class x {
 public:
 x () { 
  printf ("konstruktor\n");     
 }
};
x x_;
 
int main() {
 printf ("%x\n", main);
 getchar();
 return 0;
}
запускаем, видим:
C++
1
2
konstruktor
401290
последнее значение адрес main, у каждого своё.
Так, открываем прогу в отладчике OllyDbg, стоим на точке входа (у всех своя, у меня) 401220, ставим бряк на 401290, на main, запускаем. Видим, что бряк сработал, но конструктор не вызвался! Чуть пониже в окне дизассембра видим вызов printf с аргументом "konstruktor", то есть объект конструируется в main. Как такое может быть? Компилятор g++. Спасибо, кто откликнется.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.09.2011, 17:16
Ответы с готовыми решениями:

Почему я не могу скрыть глобальный объект document?
1. Благодаря чему мы можем писать document вместо window.document? 2. Почему следующий код выводит...

Почему в GUI нельзя использовать объект в main?
Делаю в конструкторе NetBeans, и проблема в том, что я не знаю, как использовать методы, ибо, ...

Почему ругается на не объявленный идентификатор
#include&lt;iostream&gt; #include&lt;time.h&gt; #include&lt;stdio.h&gt; #include&lt;conio.h&gt; using namespace std;...

Глобальный объект
Добрый день. Подскажите, как надо объявить класс data, так, что бы потом в начале документа...

36
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.09.2011, 18:56  [ТС] 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от Evg Посмотреть сообщение
Ятебе уже говорил, что вставать надо не на начале функции main, а на первом операторе.
Я записал, На бумажку на всякий случай, чтобы не было недоразумений. Вот как вы сказали:
Цитата Сообщение от Evg Посмотреть сообщение
По честному брекпоинт надо ставить на первый оператор main'а
По моему первый оператор main и есть начало main. Не? Если не так, уточните понятия, как это сделал я.
За printf: как бы не хотелось мне думать, что я просто "не заметил" вызова конструктороа, это не так. Брякаюсь на начало main (первый оператор или как его там), пошаговто трассирую и попадаю на printf с параметром "konstruktor". Так что увы и ах, объект создаётся в maine, что ставит с ног на голову мои и без того шаткие знания. Ребята, может в опциях компилятора надо что поправить? Я щас это смотрю уже.
0
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
13.09.2011, 19:18 22
Цитата Сообщение от kravam Посмотреть сообщение
По моему первый оператор main и есть начало main. Не?
Это не так. В начале процедуры main (с точки зрения бинарного кода и отладчика), как и в начале любой процедуры идёт так называемый пролог. Как правило это настройка стека, настройка указателей стека и прочих вещей, о которых пользователю знать незачем, потому как в языке программирования нет этих понятий (на то он и язык, чтобы не опускаться до уровня системы команд, программных соглашений и т.п.)

Цитата Сообщение от kravam Посмотреть сообщение
Если не так, уточните понятия, как это сделал я.
Какие именно понятия? Что такое "первый оператор main'а"? В твоём случае это printf (который внутри main'а).

Цитата Сообщение от kravam Посмотреть сообщение
Брякаюсь на начало main (первый оператор или как его там),
Ты уж определись, на начало main (низкоуровневое понятие) или на первый оператор main (высокоуровневое понятие)

Цитата Сообщение от kravam Посмотреть сообщение
пошаговто трассирую и попадаю на printf с параметром "konstruktor".
Внимательно читай пост #9. А ещё лучше, покажи дизассемблер своей программы

Добавлено через 1 минуту
Т.е. пост #4
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.09.2011, 19:35  [ТС] 23
Всё понятно.
Значит, ещё раз. Чтобы куда-то брякнуться, мне надо цифры какие-то. Адрес то есть. Я его получаю так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <windows.h>
#include <stdio.h>
using namespace std;
 
class x {
 public:
 x () { 
  printf ("привет\n");     
 }
};
x x_;
 
int main() {
 printf ("%x\n", main);
 getchar();
 return 0;
}
И вижу 401290 (это я первый пост дублирую)
Потом эту прогу открываю в отладчике и ставлю бряк на 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 минуты
Хотя...
Цитата Сообщение от grizlik78 Посмотреть сообщение
Если установить breakpoint на имя main или на адрес, который выводится потом в printf (это 2 разных места)
как понять брейкпонт на имя? Тебе отладчик подсказывает, где находится имя?
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 с бустом.

Цитата Сообщение от kravam Посмотреть сообщение
как понять брейкпонт на имя? Тебе отладчик подсказывает, где находится имя?
GDB без оболочек является консольным отладчиком. Командами управляется.
То есть я имел в виду команду
Код
break main
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.09.2011, 20:20  [ТС] 27
А с этим как быть?
Цитата Сообщение от grizlik78 Посмотреть сообщение
Отладчик не обязательно отражает истинное положение вещей. В ассемблерный код посмотреть надёжнее всего. Пожалуй, пойду посмотрю.
============================================
А точнее если: что же тогда выводится по
C++
1
 printf ("%x\n", main);
если ты ставишь бряк на другой адрес?

Добавлено через 11 минут
Час от часу не легче, оказывается, на main нельзя брать адрес:
http://msdn.microsoft.com/ru-r... adt5z.aspx
Cannot have its address taken.

Но тогда это кое-что проясняет (хотя g++ отношение к мелкомягким не имеет, но тем не менее), а именно: адрес main, полученный программным путём- фуфловый. Значит, может быть действительно, брякаться надо на
C++
1
printf ("%x\n", main);
но не потому, что это правильно, а потому, что больше некуда. Программно-то адрес main не получить!
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
13.09.2011, 20:40 28
Цитата Сообщение от kravam Посмотреть сообщение
Час от часу не легче, оказывается, на main нельзя брать адрес
Да, об этом я уже сказал, но это не выдумка Microsoft, это описано в стандарте C++. Впрочем, к GCC это не относится, он разрешает получение адреса и рекурсивный вызов main().

Цитата Сообщение от kravam Посмотреть сообщение
адрес main, полученный программным путём- фуфловый.
В случае VisualStudio компилятор просто не позволит получить адрес. В случае GCC адрес самый что ни на есть настоящий — начало кода функции main().

Цитата Сообщение от kravam Посмотреть сообщение
если ты ставишь бряк на другой адрес?
Как я уже говорил, я ставил breakpoint и по символическому имени, и по машинному адресу начала main. В обоих случаях конструктор уже был вызван.

Добавлено через 5 минут
Собственно, разница между этими точками останова только в том, что по символическому имени пропускается настройка стека.
0
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
13.09.2011, 21:01 29
Цитата Сообщение от kravam Посмотреть сообщение
Значит, ещё раз. Чтобы куда-то брякнуться, мне надо цифры какие-то
Единственный человеческий способ остановиться в правильной точке - это скомпилировать с отладочной информацией и установить брекпоинт в виде "break main" или "break t.c:14" (я так понимаю, что у тебя отладчик gdb). Другого не дано.

Нечеловеческий способ - это продизассемблировать программу и глазками посмотреть адрес, который будет соответствовать первому оператору (если понимаешь в ассемблере). В режиме с оптимизациями ты этого в принципе уже получить точным образом, потому как компилятор скорее всего коды перемешает и не факт, что в программе найдётся точная граница между тем, как "первый оператор уже выполнен" и "первый оператор ещё не выполнен", потому что это на языке только один оператор, а в коде это будет несколько машинных инструкций, которые могут перемешаться с инструкциями другого оператора
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
13.09.2011, 21:13 30
Цитата Сообщение от Evg Посмотреть сообщение
я так понимаю, что у тебя отладчик gdb
Так вроде ж OllyDbg у него. Фиг его знает, как там с интеграцией с кодом от MinGW. Это я GDB мучил.
0
Эксперт С++
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
13.09.2011, 21:27 31
Цитата Сообщение от grizlik78 Посмотреть сообщение
А какая, по большому счёту разница, если стандарт С++ не разрешает получение адреса функции main()? Правда как-раз именно GCC это ограничение не выполняет и разрешает рекурсивный вызов функции main() в C++.
Раньше, помнится, и борландовские компиляторы разрешали. Баловался сам. Удобно параметры командной строки обрабатывать без цикла - рекурсивным вызовом.
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
13.09.2011, 21:29  [ТС] 32
Цитата Сообщение от Evg Посмотреть сообщение
Нечеловеческий способ - это продизассемблировать программу и глазками посмотреть адрес, который будет соответствовать первому оператору (если понимаешь в ассемблере).
Там ничё сложного. Но я предпочёл всё же получить адрес для бряка программно. А вы мне опять первый оператор да первый оператор
...Вообще сказка про белого бычка. Чтобы знать первый оператор функции надо знать где эта функция начинется чтобы посмотреть её первый оператор чтобы посмотреть где она начинается чтобы...

Короче, вы не знаете.
0
бжни
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
13.09.2011, 21:39 33
Цитата Сообщение от Evg Посмотреть сообщение
Более правильным было бы сказать "до того, как исполнится первый оператор main'а". Потому как некоторые компиляторы вызов глобальных конструкторов встраивают в самое начало main'а
Цитата Сообщение от Сыроежка Посмотреть сообщение
Нет, это будет неправильно, так как это не соответсвует букве стандарта. Это разработчики компиляторов делают на свой страх и риск!
It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of
namespace scope is done before the first statement of main. If the initialization is deferred to some point
in time after the first statement of main, it shall occur before the first use of any function or object defined
in the same translation unit as the object to be initialized.31) [Example:
// – File 1 –
#include "a.h"
#include "b.h"
B b;
A::A(){
b.Use();
}
// – File 2 –
#include "a.h"
A a;
// – File 3 –
#include "a.h"
#include "b.h"
extern A a;
extern B b;
int main() {
a.Use();
b.Use();
}
It is implementation-defined whether either a or b is initialized before main is entered or whether the
initializations are delayed until a is first used in main
. In particular, if a is initialized before main is
entered, it is not guaranteed that b will be initialized before it is used by the initialization of a, that is,
before A::A is called. If, however, a is initialized at some point after the first statement of main, b will
be initialized prior to its use in A::A. ]
собственно
1
Evg
Эксперт CАвтор FAQ
21280 / 8302 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
13.09.2011, 21:55 34
Цитата Сообщение от kravam Посмотреть сообщение
Но я предпочёл всё же получить адрес для бряка программно
Я тебе уже объяснял, что адрес функции - это совсем не то. От точки входа в main до printf'а может чёрт-те сколько команд исполниться.

Цитата Сообщение от kravam Посмотреть сообщение
Короче, вы не знаете
Читай пост #29, там всё написано. Если не умеешь работать с ассемблером и не имеешь представления о том, как работает компилятор, то попросту не стоит лазить в отладчике на низком уровне (без отладочной информации).

Цитата Сообщение от kravam Посмотреть сообщение
Так что увы и ах, объект создаётся в maine
Объект вообще создаётся compile-time. А то, о чём ты говоришь, называется "инициализируется". Может статья тебе поможет, но там много букв Конструкторы и деструкторы

Добавлено через 11 минут
И ещё::

Цитата Сообщение от Evg Посмотреть сообщение
А ещё лучше, покажи дизассемблер своей программы
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
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.09.2011, 22:59
Помогаю со студенческими работами здесь

Глобальный объект
Как сделать, чтобы я создал объект, и его видел весь файл? Суть в том, что в конструктор я хочу...

Глобальный объект
Есть у меня приложение с формой Win Forms(CLR) Ну у меня весь код соответственно в .h файле. Как...

Глобальный объект
Можете объяснить такие вещи: 1)Название объекта в каждой среде разное?(то есть в...

Глобальный объект
Как сделать такое: при запуске программы (т.е. появление Главной формы) я создаю объект (коллекция)...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
37
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru