![]() |
Модераторы: bsa |
![]() ![]() ![]() |
|
Lampa24 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 12 Регистрация: 22.3.2008 Репутация: нет Всего: нет |
Криво написано , но это учебная прога. В таком виде она не проходит линкинг и в принципе это понятно . Но если добавить inline к int MyFactorial(int a) , то прога работает. Объясните плз. почему?????? Ведь inline в рекурсии компайлер игнорирует. |
|||
|
||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
не обязательно, этот эффект называется tail call(tail recursion это частный случай). В данном случае компилятор заменяет рекурсию на цикл, и делает функцию подставляемой |
|||
|
||||
Lampa24 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 12 Регистрация: 22.3.2008 Репутация: нет Всего: нет |
vinter Спасибо, но это не отвечает на основной вопрос , почему inline избавляет от ошибки ????
|
|||
|
||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
||||
|
||||
Lampa24 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 12 Регистрация: 22.3.2008 Репутация: нет Всего: нет |
Пасибо огромное!!!!!! |
|||
|
||||
Lazin |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 27 Всего: 154 |
я думаю программа не работает не из-за переполнения стека ![]()
что за ошибка? Это сообщение отредактировал(а) Lazin - 19.1.2009, 21:56 |
||||
|
|||||
Lampa24 |
|
||||||
Новичок Профиль Группа: Участник Сообщений: 12 Регистрация: 22.3.2008 Репутация: нет Всего: нет |
Какого стэка???? Фактариал 5 посчитать проблема??? А ошибка двойное определение функции NumPermutations |
||||||
|
|||||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 27 Всего: 154 |
интересно в каком месте, можешь запостить то что выдает компилтор, а не свой вольный пересказ? это я вообще не тебе |
|||
|
||||
Lampa24 |
|
|||
Новичок Профиль Группа: Участник Сообщений: 12 Регистрация: 22.3.2008 Репутация: нет Всего: нет |
Compiling... Q2a.cpp Linking... Q2a.obj : error LNK2005: "int __cdecl MyFactorial(int)" (?MyFactorial@@YAHH@Z) already defined in Q2b.obj Debug/Q2b.exe : fatal error LNK1169: one or more multiply defined symbols found Error executing link.exe. Q2b.exe - 2 error(s), 0 warning(s) Это без inline |
|||
|
||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
а причем оно тут? я про переполнение ни слова не сказал. глянь на исходник, у него ф-ия определена в ашнике |
|||
|
||||
Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 27 Всего: 154 |
ааааа ну ты сказал, что там оптимизация хвостовой рекурсии используется и я подумал что ты подумал что без этой оптимизации программа валилась с переполнением стека, а с ней работала, в принципе это возможно, если рекурсия глубокая и ф-я не определена в ашнике ![]() |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Lampa24, на будущее, чтобы подобных проблем не было, в h файл помещай только декларации структур, классов, переменных, функций, перечисления и переопределения типов, можно еще константы (на C++), а реализацию - в c/cpp файл. Просто, когда в двух или более модулях встречается реализация функций с одинаковыми именами (сигнатурами), то линкер выдает ошибку, так как он не может понять, в каком месте какая используется. Если ты помечаешь ее inline, то начинают работать несколько иные правила - линкер уже может и не знать о существовании такой функции.
|
|||
|
||||
UnrealMan |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 5 Всего: 32 |
||||
|
||||
Lampa24 |
|
||||
Новичок Профиль Группа: Участник Сообщений: 12 Регистрация: 22.3.2008 Репутация: нет Всего: нет |
А ты бы не мог подробней об этих правилах . Просто это вопрос на д\з и мне нужно объяснить почему это так. Добавлено через 1 минуту и 18 секунд
????? Это к чему уважаемый??? |
||||
|
|||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
об этом :
макрос во первых раскрывается не во время компиляции, а до. во вторых inline не более чем указание компилятору сделать функцию встраиваемой. в третьих проблема исчезает не из за того, что функция встраивается, а из за того что имена функций с inline для линкера помечены как локальные, в отличие от имен обычных функций, которые имееют внешнее связывание. |
|||
|
||||
bsa |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
В двух словах: Обычная функция записывается в 2 места объектного файла - область кода и "экспортную" таблицу символов. В области кода находится собственно "почти" машинный код (только вместо адресов вызываемых процедур и глобальных переменных, там ссылки на них или просто мусор - реальные значения подставляются на этапе компоновки), а в области таблицы символов находится запись: <сигнатура функции (считай, ее название и список параметров)> <смещение отностительно области кода> <размер кода> Когда все объектные файлы созданы из исходников, происходит их компоновка линкером. Он читает таблицу импортируемых символов (для простоты, в нее записываются все переменные и функции, которые реализованы в другом объектном файле, каждая запись ссылается на "мусор" в машинном коде), затем ищет требуемый символ (сигнатуру функции/переменной) в экспортных таблицах всех объектных файлов. Если находит, то помещает функцию в результирующий файл (т.е. уже в экзешник) и продолжает до тех пор, пока все символы не будут разрешены. Есть ключевое слово static, которое говорит компилятору, что данный объект не надо включать в экспортную таблицу. Таким образом, в программе может быть миллион одинаковых статических переменных или функциий, которые находятся в разных объектных файлах, и линкер не ругнется - он просто не будет знать о их существовании. Если ты помечаешь функцию словом inline, то (в С++) говоришь компилятору, что данная функция является встраиваемой, поэтому не надо помещать ее в экспортную таблицу (т.е. фактически функция статическая). Таким образом, даже если функцию не удалось компилятору встроить, линкер все равно о ней ничего не узнает. В языке си, будет ругаться, поэтому там надо помечать ее еще и static. P.S.: я попытался использовать простейшую терминологию. Если есть желании знать все в научной, то тебе тут объяснят. |
||||
|
|||||
UnrealMan |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 5 Всего: 32 |
Lampa24, тебе чья лапша больше нравится: vinter-a или mes-а & bsa? ![]() |
||||
|
|||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
Т.е. я был не прав, говоря, что она является фактически static. |
|||
|
||||
vinter |
|
||||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
причем тут макрося сказал, что она подобна. И что она встраивается на этапе компиляции, что непонятно? именно из-за этого.
линкер к inline функции не имеет никакого отношения, потомучто если inline пожелание было исполнено, то никакой функции нет.
bsa, а ты проверь ;) UnrealMan, хорошь стебаться, есть, что сказать - говори ![]() |
||||
|
|||||
UnrealMan |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 5 Всего: 32 |
Проблема исчезает из-за того, что исчезает нарушение правила одного определения, а задумано оно так для того, чтобы одни и те же inline-функции сразу в нескольких единицах трансляции могли встраиваться во время компиляции (не дожидаясь компоновки). |
|||
|
||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
||||
|
||||
UnrealMan |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 722 Регистрация: 30.3.2006 Репутация: 5 Всего: 32 |
||||
|
||||
baldina |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
компилятор ведет себя в соответствии со стандартом: inline функция имеет один адрес во всех единицах трансляции. технически это означает, что если где-то используется адрес функции, то компилятор генерирует (единственное) определение этой функции. что, заметьте, не мешает ему при вызове этой функции подставлять её встроенное представление вместо вызова, если компилятор считает это нужным. вот как, например, может поступить компилятор:
|
||||||
|
|||||||
vinter |
|
||||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
стандарт другое говорит
так насколько я понял: при inline будет всегда генерироваться новое определение ф-ии, в каждой еденицы трансляции(типо internal linkage чтоли?). Я правильно это понимаю или нет? Следущий вопрос: я сталкивался с ситуацией когда была средних размеров inline ф-ия которая находилась в ашнике, все работало замечательно. Но после добавления нескольких строк появилась ошибка линкера, я вв свое время решил, что это из-за того, что ф-ия перестала встраиватся и из-за этого ошибка. Как это объяснить? gcc 4.0.1 кажется.. |
||||
|
|||||
baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
не, vinter, стандарт говорит именно это. и не надо его домысливать, там четко все.
Добавлено через 5 минут и 10 секунд для начала таки переведи приведенную тобой фразу. и читай 7.1
|
|||
|
||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
baldina, ну и что? покад\жи мне в каком месте изначальнеого кода есть
и это не отменяет вопросов заданнных ранее, я ничего не домысливаю, я всего лишь пытаюсь понять. Анрыл вон знает и молчит как партизан, обиделся наверно ![]() |
|||
|
||||
baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
в изначальном коде функция определена в ашнике, включаемом в двух файлах. т.е. имеем определение ее в нескольких единицах трансляции.
покуда она не inline это нарушает правило одного определения. как только она становится inline ничего не нарушается. и ошибок компиляции нет. встраивается она или нет совершенно неважно, это деталь реализации. вариант реализации (MSVC так делает) я показал - может иметь место встраивание и не-встраивание одновременно. но это уже не относится к вопросу ![]() Добавлено через 1 минуту и 20 секунд
читай стандарт, тоже знать будешь. думаешь он молчит - время экономит? хочет что бы ты сам прочел. так полезнее. |
|||
|
||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
baldina, остается неотвеченный вопрос
остальное я понял, но не совсем понял смысл этого и еще, встроить функцию это не просто впихнуть ее код где надо, это определенный гемморой. Как тогда быть с единственнно определенной функцией, и как быть с цитаатой из стандарта приведенной мной выше. я прочел, вопросы остались. То, что полезнее не спорю, если бы не Анрыл, я бы стандарт наверно не скоро открыл ![]() |
|||
|
||||
baldina |
|
||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
какая ошибка линкера? в скольких единицах трансляции была эта функция? в скольких разных местах на диске был одноименный ашник с одноименной функцией? хорошо бы код глянуть
Скомпилить код таким образом, что бы функция была определена один раз (по единственному адресу) - это задача компилятора. Определить inline функцию в каждой единице трансляции, где она используется - обязанность программиста. Здесь нет противоречий. Это буквально то, что в стандарте. В чем вопрос? Добавлено через 4 минуты и 19 секунд vinter, стандарт содержит как требования к коду, так и гарантии программисту (требования к компилятору).
Это обязан обеспечить программист
Это обязан обеспечить компилятор |
||||||||
|
|||||||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
||||
|
||||
baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
vinter, похоже проблема из разряда "я делаю все правильно, почему не работает".
если тот код жив еще можно посмотреть и попробовать разобраться. даже интересно. |
|||
|
||||
vinter |
|
|||
![]() Explorer ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2735 Регистрация: 1.4.2006 Где: Н.Новгород Репутация: 8 Всего: 56 |
||||
|
||||
![]() ![]() ![]() |
Правила форума "C/C++: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |