2013-04-14 4 views
2

Я пытаюсь обернуть голову вокруг разработки C++, используя библиотеку SFML. Я следую учебнику (http://www.gamefromscratch.com/page/Game-From-Scratch-CPP-Edition-Part-7.aspx) и с использованием visual studio 2010.Как исправить непоследовательные Неразрешенные внешние ошибки?

Проблема, с которой я сталкиваюсь в отношении нерешенных внешних. Я действительно борюсь с этим, потому что в отличие от большинства ошибок, с которыми я сталкиваюсь, это не похоже на a) имеет какое-либо отношение к коду, и b) не ведет себя последовательно. Вместо того, чтобы дать вам конкретный пример и попросить помочь решить этот один пример, я надеюсь разработать более надежный способ атаковать эти проблемы. Однако я расскажу вам об общем распространении.

У меня есть решение с 8 файлами заголовков и 8 файлами cpp, которые соответствуют им. Решение стабильно: оно компилируется и запускается без ошибок и предупреждений.

Я пойду в файл заголовка и добавьте следующую строку:

виртуальная пустота DoNothing();

Я затем в файл сопоставления CPP и написать метод:

аннулируются DoNothing() {};

Скомпилировать и запустить и получить 5 нерешенных внешних ошибок. Они не указывают на какую-либо строку кода, поэтому я действительно не знаю, как их исправить, но я, очевидно, сделал что-то не так. Справедливо. Попытавшись вернуться в стабильное состояние, я удаляю две строки кода, которые я вставил, и скомпилируйте. Несмотря на то, что код идентичен последнему стабильному состоянию, я получаю те же нерешенные внешние ошибки.

Пробуя случайные вещи, я перехожу в другой файл cpp и отменяю порядок двух включенных файлов заголовков. Игра теперь компилируется. Если я переключу порядок входящих файлов заголовков обратно, он скомпилируется.

Какие черты нерешенные внешние ошибки? Почему они не ведут себя последовательно с кодом, который я ввел? Как я прочитал их, чтобы узнать, в чем проблема, и как мне избежать их в первую очередь?

спасибо.

ps: Если есть более конкретные детали, я должен предоставить, пожалуйста, просто дайте мне знать.

+2

В вашем примере это похоже, что вы не квалифицируете имя. Вероятно, это должно быть 'void SomeClass :: DoNothing() {}' –

+1

, пожалуйста, предоставьте [SSCCE] (http://sscce.org/) – TemplateRex

ответ

1

«Неразрешенные внешние» ошибки означают, что ваш код ссылается на что-то (обычно это функция или метод, но может быть и переменной), которой не существует. Это связь ошибки, и не скомпилировать ошибки; поэтому вы не получаете номер строки и более полезные сообщения об ошибках.

Позвольте мне дать вам немного о том, как C++ код включается в исполняемый файл (и иметь в виду, что я упрощающего вещи немного.)

Каждый ++ исходный файл C (а не заголовок файла) в ваш проект составляется отдельно. Файл «.cpp» и все его заголовки скомпилированы в так называемый объектный файл или код объекта. (Эти файлы имеют расширение «.obj» или «.o».) Вы также можете думать о библиотечных файлах (то есть «.lib» -файлах в Windows и «.a» -файлах в Linux) как набор этих объектных файлов , сохраненный для последующего использования.

Для создания исполняемых программ (напр.EXE или DLL-файл в Windows) все эти объектные файлы: связаны вместе: voila!

Теперь важно то, что каждый исходный файл скомпилирован в изоляции и не зависит от других исходных файлов. Таким образом, если код в одном файле вызывает функцию, реализованную в другом файле, компилятор не увидит фактическое тело этой функции и может только предположить, что до тех пор, пока отображается декларация вызываемой функции (т. Е. прототип , т. е. строку, которую вы пишете в заголовках), то эти файлы в конечном итоге будут связаны друг с другом и оставят задачу фактически сделать вызов компоновщику. Это обычно означает, что до тех пор, пока вы включаете правильные заголовки, ваш компилятор будет счастлив.

Но компоновщик будет более стойким и педантичным. Во время соединения вам действительно нужно предоставить тело (то есть реализацию) всех функций, которые вы используете во всем проекте. Это ваша задача - убедиться, что все нужные объектные файлы и библиотеки связаны друг с другом, а реализация каждой используемой функции существует где-то среди них ровно один раз (не более, не менее).

Это приводит нас к вашей проблеме. Когда вы получаете ошибку «неразрешенного внешнего» компоновщика, это означает, что тело вызываемой функции не существует нигде в объектных файлах и библиотеках, которые вы связываете вместе.

Очевидно, что происходит одна из двух вещей. Либо вы включили заголовок для внешней библиотеки, но и забыли связать в самом файле библиотеки (что не является вашей проблемой здесь), или вы объявили (то есть создали прототип для) функцию, но забыли реализовать ее тело ,

Имейте в виду, что компоновщик здесь действительно строг. Если вы заявляете что-то подобное в своем классе:

class Foo { 
    void bar (int x); 
}; 

, а затем в файле «.cpp», реализовать эту функцию:

void bar (int x) 
{ 
    // Do nothing 
} 

тогда вы получите неразрешенный внешний ошибку, если вы на самом деле вызовите Foo::bar() в любом месте вашей программы, потому что реализованный bar() не является методом Foo (вы должны были реализовать void Foo::bar (int x) {}.) Аналогичные вещи случаются, если вы слегка ошибаетесь или получаете тип аргументов неправильно или еще что-то.

Чтение ошибок компоновщика и определение смысла из них может быть твердым. Иногда имя, на которое жалуется компоновщик («символ», который он говорит, что он не может найти), все искажено до неузнаваемости. Это связано с * Application Binary Interface * s (ABI) и несколькими десятилетиями истории и приоритета. В любом случае, большую часть времени, если вы посмотрите внимательно и сообщение об ошибке ссылки, вы можете увидеть, что такое имя функции, и проверить свой код (или библиотеки) и повторите попытку.

Кроме того, хотя это редкость, иногда бывает так, что для решения некоторых проблем с ссылками вы должны прибегнуть к полной перестройке своего проекта.

0

Каждый раз, когда я видел подобное поведение, это было связано с круговой ссылкой между проектами. Например, проект A имеет ссылку на объект/символ, реализованный в проекте B, в то время как проект B имеет ссылку на объект/символ из проекта A. Каждый раз, когда вы строите свое решение, инструменты должны скомпилировать один проект сначала, затем другой.Если вы внесете изменения во второй проект, который будет скомпилирован, первый не сможет увидеть изменения в первом раунде компиляций, и сборка завершится неудачно. Если вам удастся вручную построить проект B (против устаревшей копии библиотеки B), тогда решение начнет правильно строить. Возможны более сложные циклы (например, A зависит от B, который зависит от C, который зависит от A). Вы не упоминаете несколько проектов явно, но я уверен, вы их имеете.

Эти циркулярные ссылки распространены на крупных решениях, которые были вокруг в течение длительного времени и со временем медленно росли. Люди получают в привычку добавлять ссылки от всего ко всему, потому что они нуждаются в одной функции от здесь, на структуру из там ...

выследить этих зависимостей. Вы должны иметь возможность выполнить полную чистую перестройку только из исходного кода. Дерево вашей зависимости должно выглядеть так ... Ну, дерево; а не график.

 Смежные вопросы

  • Нет связанных вопросов^_^