Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 17, средняя оценка - 4.82
kravam
быдлокодер
1691 / 878 / 44
Регистрация: 04.06.2008
Сообщений: 5,423
#1

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

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

Всё просто, имеем код:
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++. Спасибо, кто откликнется.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.09.2011, 17:16     Почему глобальный объект, объявленный до main, конструируется в ней?
Посмотрите здесь:

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

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

Глобальный объект класса - C++
Ребят, написал класс для реализации очереди на основе массива в отдельном юните, теперь мне нужно в другом получить объект класса, который...

Глобальный объект класса - C++
Добрый вечер всем!) Вообщем суть такая: пишу статическую библиотеку, которая состоит из кучи файлов. Есть класс, конструктор которого...

Динамический глобальный объект. - C++
Здравствуйте. Пишу Auto-Clicker . Текущая версия содержит заранее созданный массив объектов класса &quot;TClickBase&quot; в каждом объекте хранятся...

Правильно созданный глобальный объект - C++
Необходимо создать создать несколько объектов классов глобально. Я делаю: Создаю h-файл. в нем объявляю(создаю) объекты. И в срр -...

Инициализированный объект в main не виден в других функциях - C++
void display() { clear(); rocket.draw(); //ОШИБКА glFlush(); glutSwapBuffers(); _time++; } int main()

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
kravam
быдлокодер
1691 / 878 / 44
Регистрация: 04.06.2008
Сообщений: 5,423
13.09.2011, 18:56  [ТС]     Почему глобальный объект, объявленный до main, конструируется в ней? #21
Цитата Сообщение от Evg Посмотреть сообщение
Ятебе уже говорил, что вставать надо не на начале функции main, а на первом операторе.
Я записал, На бумажку на всякий случай, чтобы не было недоразумений. Вот как вы сказали:
Цитата Сообщение от Evg Посмотреть сообщение
По честному брекпоинт надо ставить на первый оператор main'а
По моему первый оператор main и есть начало main. Не? Если не так, уточните понятия, как это сделал я.
За printf: как бы не хотелось мне думать, что я просто "не заметил" вызова конструктороа, это не так. Брякаюсь на начало main (первый оператор или как его там), пошаговто трассирую и попадаю на printf с параметром "konstruktor". Так что увы и ах, объект создаётся в maine, что ставит с ног на голову мои и без того шаткие знания. Ребята, может в опциях компилятора надо что поправить? Я щас это смотрю уже.
Evg
Эксперт CАвтор FAQ
17470 / 5708 / 363
Регистрация: 30.03.2009
Сообщений: 15,670
Записей в блоге: 26
13.09.2011, 19:18     Почему глобальный объект, объявленный до main, конструируется в ней? #22
Цитата Сообщение от kravam Посмотреть сообщение
По моему первый оператор main и есть начало main. Не?
Это не так. В начале процедуры main (с точки зрения бинарного кода и отладчика), как и в начале любой процедуры идёт так называемый пролог. Как правило это настройка стека, настройка указателей стека и прочих вещей, о которых пользователю знать незачем, потому как в языке программирования нет этих понятий (на то он и язык, чтобы не опускаться до уровня системы команд, программных соглашений и т.п.)

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

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

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

Добавлено через 1 минуту
Т.е. пост #4
kravam
быдлокодер
1691 / 878 / 44
Регистрация: 04.06.2008
Сообщений: 5,423
13.09.2011, 19:35  [ТС]     Почему глобальный объект, объявленный до main, конструируется в ней? #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 на корню зарубает мою тягу к знаниям.
grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
13.09.2011, 19:43     Почему глобальный объект, объявленный до main, конструируется в ней? #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 не обнаружено.
kravam
быдлокодер
1691 / 878 / 44
Регистрация: 04.06.2008
Сообщений: 5,423
13.09.2011, 19:58  [ТС]     Почему глобальный объект, объявленный до main, конструируется в ней? #25
У меня 3.4.2, можешь скинуть куда-нибудь?

Добавлено через 3 минуты
Хотя...
Цитата Сообщение от grizlik78 Посмотреть сообщение
Если установить breakpoint на имя main или на адрес, который выводится потом в printf (это 2 разных места)
как понять брейкпонт на имя? Тебе отладчик подсказывает, где находится имя?
grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
13.09.2011, 20:00     Почему глобальный объект, объявленный до main, конструируется в ней? #26
Кого скинут? 3.4.5, на котором я экспериментировал, входит в стостав wxDev-C++.
Версия 4.5.2 с sourceforge, кажется. У niXman в подписи можно найти 4.6.1 с бустом.

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

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

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

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

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

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

Нечеловеческий способ - это продизассемблировать программу и глазками посмотреть адрес, который будет соответствовать первому оператору (если понимаешь в ассемблере). В режиме с оптимизациями ты этого в принципе уже получить точным образом, потому как компилятор скорее всего коды перемешает и не факт, что в программе найдётся точная граница между тем, как "первый оператор уже выполнен" и "первый оператор ещё не выполнен", потому что это на языке только один оператор, а в коде это будет несколько машинных инструкций, которые могут перемешаться с инструкциями другого оператора
grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
13.09.2011, 21:13     Почему глобальный объект, объявленный до main, конструируется в ней? #30
Цитата Сообщение от Evg Посмотреть сообщение
я так понимаю, что у тебя отладчик gdb
Так вроде ж OllyDbg у него. Фиг его знает, как там с интеграцией с кодом от MinGW. Это я GDB мучил.
ValeryLaptev
Эксперт С++
1035 / 814 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
13.09.2011, 21:27     Почему глобальный объект, объявленный до main, конструируется в ней? #31
Цитата Сообщение от grizlik78 Посмотреть сообщение
А какая, по большому счёту разница, если стандарт С++ не разрешает получение адреса функции main()? Правда как-раз именно GCC это ограничение не выполняет и разрешает рекурсивный вызов функции main() в C++.
Раньше, помнится, и борландовские компиляторы разрешали. Баловался сам. Удобно параметры командной строки обрабатывать без цикла - рекурсивным вызовом.
kravam
быдлокодер
1691 / 878 / 44
Регистрация: 04.06.2008
Сообщений: 5,423
13.09.2011, 21:29  [ТС]     Почему глобальный объект, объявленный до main, конструируется в ней? #32
Цитата Сообщение от Evg Посмотреть сообщение
Нечеловеческий способ - это продизассемблировать программу и глазками посмотреть адрес, который будет соответствовать первому оператору (если понимаешь в ассемблере).
Там ничё сложного. Но я предпочёл всё же получить адрес для бряка программно. А вы мне опять первый оператор да первый оператор
...Вообще сказка про белого бычка. Чтобы знать первый оператор функции надо знать где эта функция начинется чтобы посмотреть её первый оператор чтобы посмотреть где она начинается чтобы...

Короче, вы не знаете.
alex_x_x
бжни
2445 / 1650 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
13.09.2011, 21:39     Почему глобальный объект, объявленный до main, конструируется в ней? #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. ]
собственно
Evg
Эксперт CАвтор FAQ
17470 / 5708 / 363
Регистрация: 30.03.2009
Сообщений: 15,670
Записей в блоге: 26
13.09.2011, 21:55     Почему глобальный объект, объявленный до main, конструируется в ней? #34
Цитата Сообщение от kravam Посмотреть сообщение
Но я предпочёл всё же получить адрес для бряка программно
Я тебе уже объяснял, что адрес функции - это совсем не то. От точки входа в main до printf'а может чёрт-те сколько команд исполниться.

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

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

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

Цитата Сообщение от Evg Посмотреть сообщение
А ещё лучше, покажи дизассемблер своей программы
kravam
быдлокодер
1691 / 878 / 44
Регистрация: 04.06.2008
Сообщений: 5,423
13.09.2011, 22:49  [ТС]     Почему глобальный объект, объявленный до main, конструируется в ней? #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. До свидания, друзья. До новых встреч!
alex_x_x
бжни
2445 / 1650 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
13.09.2011, 22:53     Почему глобальный объект, объявленный до main, конструируется в ней? #36
kravam, писать программы, поведение которых зависит от компилятора - зло
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
13.09.2011, 22:59     Почему глобальный объект, объявленный до main, конструируется в ней?
Еще ссылки по теме:

Глобальный вектор. Почему на выходе этот массив пуст? - C++
юзаю либу вектор. почему на выходе этот массив пуст? std::vector&lt;int&gt; qw;//global int main() { int i=1; qw.push_back(i); ...

Как передавать объект класса в методе main, чтобы конструктор не вызывался 2 раза? - C++
Проблемы заключаются в следующем: есть класс для создания записи и класс для хранения массива этих записей. Так вот, как передавать объект...

_tmain(...) вместо main(...) Почему? - C++
только что установил MVS 2010. когда создаю новы фаил, то вместо привычной мне функции main() там функция _tmain(int argc, _TCHAR* argv)....

Почему не хочет возвращать main() ? - C++
Вот практикуюсь в C++, а тут return main(); не хочет работать - красным main() подчёркивает. Почему здесь ошибка, подскажите пожалуйста. ...

Почему в main(); При вызове объекта не выводится в консоль? - C++
Задача: Цифровой счетчик, это переменная с ограниченным диапазоном. Значение которой сбрасывается, когда ее целочисленное значение...


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

Или воспользуйтесь поиском по форуму:
kravam
быдлокодер
1691 / 878 / 44
Регистрация: 04.06.2008
Сообщений: 5,423
13.09.2011, 22:59  [ТС]     Почему глобальный объект, объявленный до main, конструируется в ней? #37
Да не, поведение не зависело, вы невнимательно читали тему или вообще не читали её. Просто я мысля обнаружил расхождение между теорией и практикой и решил его решить.
Yandex
Объявления
13.09.2011, 22:59     Почему глобальный объект, объявленный до main, конструируется в ней?
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru