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

C++

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 81, средняя оценка - 4.69
Evg
Эксперт CАвтор FAQ
17411 / 5649 / 355
Регистрация: 30.03.2009
Сообщений: 15,467
Записей в блоге: 26
#1

[Задача] Объясните результат исполнения программы - C++

10.10.2011, 18:04. Просмотров 9793. Ответов 21

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Файл t1.cc
#include <iostream>
 
class C
{
    int x;
 
  public:
    C() { x = 10; }
    int get() { return x; }
};
 
int main (void)
{
  C c;
 
  std::cout << c.get() << std::endl;
  return 0;
}
C++
1
2
3
4
5
6
7
8
9
10
11
// Файл t2.cc
class C
{
  public:
    int get();
};
 
int C::get()
{
  return 20;
}
Код
$ g++ t1.cc t2.cc
$ ./a.out
20
Задача из разряда "трудноуловимые ошибки"
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
aeshes
439 / 202 / 13
Регистрация: 07.10.2011
Сообщений: 462
10.10.2011, 18:13     [Задача] Объясните результат исполнения программы #2
а если порядок файлов в строке
g++ t1.cc t2.cc
поменять?
Chelioss
179 / 179 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
10.10.2011, 18:35     [Задача] Объясните результат исполнения программы #3
В Visual studio 2008 ошибка компиляции. Два раза написан метод get.
Или я не понял о чем вы?
easybudda
Эксперт С++
9456 / 5469 / 927
Регистрация: 25.07.2009
Сообщений: 10,495
10.10.2011, 19:21     [Задача] Объясните результат исполнения программы #4
Evg, и действительно, как это оно у Вас вообще скомпилировалось?
Код
$ g++ -o t t1.cc t2.cc
/cygdrive/c/DOCUME~1/andrew/LOCALS~1/Temp/ccPKWOoS.o:t2.cc:(.text+0x0): multiple
 definition of `C::get()'
/cygdrive/c/DOCUME~1/andrew/LOCALS~1/Temp/cct23V89.o:t1.cc:(.text$_ZN1C3getEv[C:
:get()]+0x0): first defined here
collect2: ld returned 1 exit status
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
10.10.2011, 19:28     [Задача] Объясните результат исполнения программы #5
У меня тоже всё компилируется, и тоже выводит 20
Забавно. Причем если main перенести в другую единицу трансляции, ничего не меняется.
И ещё вот параллельно возник такой вопрос (меняем только t1.сс:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Файл t1.cc
#include <iostream>
 
class C
{
    int x;
 
  public:
    C() { x = 10; }
    int get() { return x; }
};
 
int main (void)
{
  C c();
 
  std::cout << c.get() << std::endl;
  return 0;
}
Почему-то выдаёт ошибку error: request for member ‘get’ in ‘c’, which is of non-class type ‘C()’
easybudda
Эксперт С++
9456 / 5469 / 927
Регистрация: 25.07.2009
Сообщений: 10,495
10.10.2011, 19:36     [Задача] Объясните результат исполнения программы #6
Цитата Сообщение от #pragma Посмотреть сообщение
Забавно
Ага... На бсде тоже скомпилировалось и тоже 20 вывело...
Код
[andrew@server2 ~/bin]$ g++ -o t t1.cc t2.cc
[andrew@server2 ~/bin]$ ./t
20
Загадка...
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
10.10.2011, 19:51     [Задача] Объясните результат исполнения программы #7
Странно, когда перенёс x в public, один раз таки выдало 10...
Такое ощущение, что при вызове c.get() вызывается конструктор объекта класса из t2.cc
Evg
Эксперт CАвтор FAQ
17411 / 5649 / 355
Регистрация: 30.03.2009
Сообщений: 15,467
Записей в блоге: 26
10.10.2011, 20:27  [ТС]     [Задача] Объясните результат исполнения программы #8
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от aeshes Посмотреть сообщение
а если порядок файлов в строке
g++ t1.cc t2.cc
поменять?
От порядка не зависит

Цитата Сообщение от Chelioss Посмотреть сообщение
В Visual studio 2008 ошибка компиляции. Два раза написан метод get.
Или я не понял о чем вы?
Это implementation-dependend фича. Точнее, с точки зрения стандарта в тесте undefined behaviour, но как оно себя проявит - зависит от технических особенностей компилятора. Конкретно в данном случае в linux'е используется бинарный формат elf, а потому компилятор настроен одним образом. В винде используется более допотопный формат файла, из-за которого компиляторы настраиваются по другому

Цитата Сообщение от easybudda Посмотреть сообщение
Evg, и действительно, как это оно у Вас вообще скомпилировалось?
В твоём случае тоже винда

Добавлено через 3 минуты
Тест представляет собой сокращённый тестовый пример, об который конкретно споткнулись в реальной жизни: в программу локально включили описание класса, имя которого (и имя метода), как оказалось, совпало с уже существующим, но продвинутый gcc оказался бессилен с точки зрения диагностики ошибки. Вероятность таким образом вляпаться не такая уж и большая, но, как показала практика, она отлична от нуля

Добавлено через 7 минут
Упрощённый вариант двух файлов с той же выдачей:

C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
 
inline int func (void)
{
  return 10;
}
 
int main (void)
{
  std::cout << func() << std::endl;
  return 0;
}
C++
1
2
3
4
int func (void)
{
  return 20;
}
Net_Wanderer
235 / 208 / 19
Регистрация: 08.06.2011
Сообщений: 467
10.10.2011, 20:39     [Задача] Объясните результат исполнения программы #9
Цитата Сообщение от #pragma Посмотреть сообщение
Почему-то выдаёт ошибку error: request for member ‘get’ in ‘c’, which is of non-class type ‘C()’
компилятор определяет
C++
1
C c();
как прототип функции, которая принимает void и возвращает объект типа C
Evg
Эксперт CАвтор FAQ
17411 / 5649 / 355
Регистрация: 30.03.2009
Сообщений: 15,467
Записей в блоге: 26
11.10.2011, 10:43  [ТС]     [Задача] Объясните результат исполнения программы #10
Сообщение было отмечено автором темы, экспертом или модератором как ответ
объяснение
Всё растёт из того, что стандарт Си++ требует того, чтобы inline-функции были multiply defined. Об этом я пояснял в Зачем нужен inline посты 6 и 11. Метод функции, описанный внутри тела класса, всегда является inline, даже если явно это не написано. gcc под системами с поддержкой elf'а реализует это свойство через weak-символы. В данном примере в первом файле мы имеем метод или функцию, определённую как weak, а во втором файле - метод или функцию с тем же манглированным именем, но уже честный global. Итого на линковке получается, что при разрешении ссылок global всегда перебивает weak

С нуля понять что такое weak несколько сложно, в своё время пояснял на более-менее живом примере: http://www.cyberforum.ru/cpp-experts/thread46472.html


Добавлено через 5 минут
Как-то сумбурно пояснил, но для доходчивого пояснения надо рассказать про слишком многие вещи

Добавлено через 4 минуты
В догонку к пояснению
gcc через примерно такой же способ реализует шаблоны. Все шаблонные функции и переменные являются weak'ами, а потому когда они цепляются из инклюдов, то в каждом модуле получается функция с одним и тем же именем. Но за счёт weak'а на линковке отбрасывается всё, кроме одного экземпляра. А вот если есть специализация, то она строится как global, а потому перебивает все weak'и. И две специализации уже сделать нельзя, потому как два global'а уже конфликтуют друг с другом


Добавлено через 10 часов 25 минут
Совсем забыл, что про inline я уже как-то рассказывал. См. Неочевидные ответы на простые вопросы раздел 7.2
thick_int
Заблокирован
18.11.2011, 06:16     [Задача] Объясните результат исполнения программы #11
Что-то уж очень противоречивое.
А как все это согласуется с тем, что любой объект в программе может быть определен только один раз.
Здесь явно это правило нарушено.
Evg
Эксперт CАвтор FAQ
17411 / 5649 / 355
Регистрация: 30.03.2009
Сообщений: 15,467
Записей в блоге: 26
22.11.2011, 13:38  [ТС]     [Задача] Объясните результат исполнения программы #12
Цитата Сообщение от thick_int Посмотреть сообщение
Что-то уж очень противоречивое.
А как все это согласуется с тем, что любой объект в программе может быть определен только один раз.
Здесь явно это правило нарушено.
Объект определён ровно один раз. А два раза определён метод. Если ты два раза напишешь функцию на Си, то у тебя поломается на линковке. А здесь исходник содержит ошибку, но на линковке ошибка не проявилась. Так вот устроен язык Си++, что некоторые из реалиаций языка оказываются ненадёжными в этом плане. Потому что придумать язык мало, надо ещё и понимать, как будет работать компилятор с него и какие при этом могут оказаться подводные камни
thick_int
Заблокирован
22.11.2011, 18:22     [Задача] Объясните результат исполнения программы #13
Ну уж не знаю, каким Вы компилятором пользуетесь, но я все таки не поленился перекопировал код Вашей так называемой ошибки и вот, что выдает VS2010

Ошибка 1 error LNK2005: "public: int __thiscall C::get(void)" (?get@C@@QAEHXZ) уже определен в c22.obj c:\Users\...\documents\visual studio 2010\Projects\ErrProj\ErrProj\ErrProj.obj

Ошибка 2 error LNK1169: обнаружен многократно определенный символ - один или более c:\users\...\documents\visual studio 2010\Projects\ErrProj\Debug\ErrProj.exe 1

Так что никакаяя это не трудноуловимая ошибка, а сечется компилятором влегкую.
silent_1991
Эксперт С++
4956 / 3032 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
22.11.2011, 19:10     [Задача] Объясните результат исполнения программы #14
thick_int, вы вообще читаете то, что вам пишут? Я вам помогу:
1
Цитата Сообщение от Evg Посмотреть сообщение
Так вот устроен язык Си++, что некоторые из реалиаций языка оказываются ненадёжными в этом плане
2 GOTO 1
thick_int
Заблокирован
22.11.2011, 19:20     [Задача] Объясните результат исполнения программы #15
Ну хорошо, Вы уж извините великодушно.
Но все же ради интереса укажите тот ущербный компилятор, который такую лажу не просекает.
Evg
Эксперт CАвтор FAQ
17411 / 5649 / 355
Регистрация: 30.03.2009
Сообщений: 15,467
Записей в блоге: 26
22.11.2011, 20:47  [ТС]     [Задача] Объясните результат исполнения программы #16
Цитата Сообщение от thick_int Посмотреть сообщение
Но все же ради интереса укажите тот ущербный компилятор, который такую лажу не просекает
Ты вообще читаешь, что в теме пишут?
thick_int
Заблокирован
22.11.2011, 23:54     [Задача] Объясните результат исполнения программы #17
Да Вы знаете, я так всего то с C++ знаком где-то месяц.
Конечно, еще разбираюсь слабо.
Вы уж так строго не судите новичка.

А что в теме написано, я вот так это и понял, как пишу.
Evg
Эксперт CАвтор FAQ
17411 / 5649 / 355
Регистрация: 30.03.2009
Сообщений: 15,467
Записей в блоге: 26
23.11.2011, 10:43  [ТС]     [Задача] Объясните результат исполнения программы #18
Пока сентенция сводится к тому, что виндузовые компиляторы ругаются на линковке, а юниксовые - нет. Потому что там и там используются разный формат исполняемого файла, и под виндой, где используется более ущербный формат, не проходят такие финты ушами, которые возможны под юниксом.

Ну и так, для общего сведения. "g++" - это имя компилятора
novi4ok
550 / 503 / 8
Регистрация: 23.07.2009
Сообщений: 2,359
Записей в блоге: 1
28.11.2011, 01:16     [Задача] Объясните результат исполнения программы #19
Цитата Сообщение от Evg Посмотреть сообщение
Пока сентенция сводится к тому, что виндузовые компиляторы ругаются на линковке, а юниксовые - нет. Потому что там и там используются разный формат исполняемого файла, и под виндой, где используется более ущербный формат, не проходят такие финты ушами, которые возможны под юниксом.
подробнее изложи, в чем бОльшая ущербность формата. проиллюстрируй на примере этого случая. это интересно.

пока мне кажется все это раздражением при попытке завинтить шуруп с прямым шлицом крестообразной отверткой. формат то ли отвертки, то ли шурупа - определенно ущербный.

об обобщении "виндузовые компиляторы". недавно было решено старый проект, сделанный под nt vs6 (mfc) развивать дальше ("ведь он уже есть, и успешно работает", почему не использовать оттуда куски, такой франкенштейн создать, и к нему осовремененного добавить, и будет хорошо). на то, чтобы сделать его компилируемым под vs2010, двое пахали одну неделю. потом еще столько же ушло на то, чтобы оно снова заработало. и бой продолжается. постепенно отрезаются омертвевшие части, заменяются новыми. затраты уже, по-моему, превысили затраты на новую разработку. а "всего лишь другой компилятор". и тоже виндоузовый.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
28.11.2011, 11:03     [Задача] Объясните результат исполнения программы
Еще ссылки по теме:

C++ Объясните результат работы следующей программы
C++ Определение функции во время исполнения программы
Объясните код программы C++
Объясните пожалуйста результат работы программы C++
C++ Объясните непрогнозируемый результат переполнение типа char

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

Или воспользуйтесь поиском по форуму:
Evg
Эксперт CАвтор FAQ
17411 / 5649 / 355
Регистрация: 30.03.2009
Сообщений: 15,467
Записей в блоге: 26
28.11.2011, 11:03  [ТС]     [Задача] Объясните результат исполнения программы #20
Цитата Сообщение от novi4ok Посмотреть сообщение
подробнее изложи, в чем бОльшая ущербность формата. проиллюстрируй на примере этого случая. это интересно
Это был всего лишь пас назад

Цитата Сообщение от thick_int Посмотреть сообщение
Но все же ради интереса укажите тот ущербный компилятор, который такую лажу не просекает
Добавлено через 4 минуты
Цитата Сообщение от novi4ok Посмотреть сообщение
а "всего лишь другой компилятор". и тоже виндоузовый
Не поверишь, но в линуксе будет то же самое. И дело не только в компиляторе, но и в библиотеках и в интерфейсах операционной системы, и в изменившихся стандартах языка. То бишь на современной операционке скомпилять большую программу 10 летней давности (особенно если на Си++ написано)

Цитата Сообщение от novi4ok Посмотреть сообщение
об обобщении "виндузовые компиляторы"
Это не обобщение, а эмпирическая сентенция на текущий момент. По результату того, где данный пример запускался. И дело не в компиляторе, а в том, как компилятор использует возможности бинарного формата, используемого в винде и в линухе
Yandex
Объявления
28.11.2011, 11:03     [Задача] Объясните результат исполнения программы
Ответ Создать тему
Опции темы

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