Ошибка неразрешенный внешний символ visual studio

Обновлено: 04.07.2024

Скомпилированный код создает ссылку или вызов символа. Символ не определен ни в одной из библиотек или объектных файлов, поиск которого осуществляется компоновщиком.

Существует множество способов получения ошибок LNK2001. Все они используют ссылку на функцию или переменную, которую компоновщик не может Разрешить, или найти определение для. Компилятор может определить, когда код не объявляет символ, но не в том случае, если он не определен . Это связано с тем, что определение может находиться в другом исходном файле или библиотеке. Если код ссылается на символ, но он никогда не определен, компоновщик создает ошибку.

Что такое неразрешенный внешний символ?

Символ — это внутреннее имя функции или глобальной переменной. Это форма имени, используемая или определенная в скомпилированном объектном файле или библиотеке. Глобальная переменная определяется в объектном файле, где для него выделяется хранилище. Функция определена в объектном файле, где размещается скомпилированный код для тела функции. Внешний символ является ссылкой в одном файле объекта, но определен в другой библиотеке или объектном файле. Экспортированный символ — это открытый объект, который становится общедоступным для файлового файла или библиотеки, определяющей его.

Для создания приложения или библиотеки DLL в каждом используемом символе должно быть определено определение. Компоновщик должен Разрешить или найти определение сопоставления для каждого внешнего символа, на который ссылается каждый файл объекта. Компоновщик создает ошибку, если не удается разрешить внешний символ. Это означает, что компоновщику не удалось найти соответствующее определение экспортированного символа в любом из связанных файлов.

Проблемы компиляции и компоновки

Эта ошибка может возникать:

Если в проекте отсутствует ссылка на библиотеку (. LIB) или Object (. OBJ-файл). Чтобы устранить эту проблему, добавьте в проект ссылку на требуемую библиотеку или файл объекта. Дополнительные сведения см. в разделе lib files as input компоновщика.

Если проект содержит ссылку на библиотеку (. LIB) или Object (. OBJ), который, в свою очередь, требуются символы из другой библиотеки. Это может произойти даже в том случае, если не вызываются функции, вызывающие зависимость. Чтобы устранить эту проблему, добавьте в проект ссылку на другую библиотеку. Дополнительные сведения см. в разделе понимание классической модели для связывания: использование символов в качестве пути.

При использовании параметров /NODEFAULTLIB или /Zl . При указании этих параметров библиотеки, содержащие требуемый код, не будут связаны с проектом, если они не включены явным образом. Чтобы устранить эту проблему, явно включите все библиотеки, используемые в командной строке компоновки. Если при использовании этих параметров отображается множество отсутствующих имен функций CRT или стандартной библиотеки, явно включите библиотеки CRT и библиотеки стандартных библиотек или файлы библиотеки в ссылку.

При компиляции с параметром /CLR . Возможно, отсутствует ссылка на .cctor . Дополнительные сведения об устранении этой проблемы см. в разделе Инициализация смешанных сборок.

Если при построении отладочной версии приложения вы связываетесь с библиотеками в режиме выпуска. Аналогично, если вы используете параметры /MTD или /MDD или определяете, _DEBUG а затем связываетесь с библиотеками выпусков, то во многих других случаях следует рассчитывать на множество потенциальных неразрешенных внешних значений. Связывание сборки в режиме выпуска с отладочными библиотеками также вызывает аналогичные проблемы. Чтобы устранить эту проблему, убедитесь, что вы используете отладочные библиотеки в отладочных сборках и розничных библиотеках в ваших розничных сборках.

Если код ссылается на символ из одной версии библиотеки, но вы связываете другую версию библиотеки. Как правило, нельзя смешивать объектные файлы или библиотеки, созданные для разных версий компилятора. Библиотеки, поставляемые в одной версии, могут содержать символы, которые не могут быть найдены в библиотеках, включенных в другие версии. Чтобы устранить эту проблему, создайте все объектные файлы и библиотеки с одной и той же версией компилятора, прежде чем связывать их друг с другом. Дополнительные сведения см. в разделе C++ двоичная совместимость 2015-2019.

Если пути к библиотекам устарели. в диалоговом окне средства > параметры > проекты > VC++ каталоги в области выбор файлов библиотеки можно изменить порядок поиска в библиотеке. Папка Компоновщик в диалоговом окне страницы свойств проекта может также содержать неактуальные пути.

при установке нового Windows SDK (возможно, в другое расположение). Необходимо обновить порядок поиска библиотеки, чтобы он указывал на новое расположение. Как правило, путь следует поместить в новый каталог include и lib для пакета SDK перед расположением Visual C++ по умолчанию. Кроме того, проект, содержащий внедренные пути, может по-прежнему указывать на старые пути, которые являются допустимыми, но устарели. Обновите пути для новых функций, добавленных новой версией, которая установлена в другое расположение.

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

Проблемы кодирования

Эта ошибка может быть вызвана следующими причинами.

Несовпадение регистра в исходном коде или файле определения модуля (DEF). Например, если вы назначите переменную var1 в одном исходном файле C++ и попытаетесь получить к ней доступ VAR1 , как в другой, возникает эта ошибка. Чтобы устранить эту проблему, используйте согласованное написание имен и имена регистров.

Проект, использующий встраивание функций. Это может произойти при определении функций inline в исходном файле, а не в файле заголовка. Встроенные функции не отображаются за пределами исходного файла, который их определяет. Чтобы устранить эту проблему, определите встроенные функции в заголовках, где они объявляются.

Вызов функции C из программы на языке C++ без использования extern "C" объявления для функции C. Компилятор использует разные внутренние соглашения об именовании символов для кода C и C++. Внутреннее имя символа — это то, что ищет компоновщик при разрешении символов. Чтобы устранить эту проблему, используйте extern "C" обертку для всех объявлений функций C, используемых в коде C++, в результате чего компилятор должен использовать внутреннее соглашение об именовании языка c для этих символов. Параметры компилятора /TP и /TC заставляют компилятор компилировать файлы как C++ или C соответственно, независимо от расширения имени файла. Эти параметры могут привести к тому, что имена внутренних функций отличаются от предполагаемых.

Попытка сослаться на функции или данные, у которых нет внешней компоновки. В C++ встроенные функции и const данные имеют внутреннюю компоновку, если явно не указано в качестве extern . Чтобы устранить эту проблему, используйте явные extern объявления для символов, которые ссылаются вне определяющего исходного файла.

Отсутствует тело функции или определение переменной . Эта ошибка часто возникает при объявлении, но не определении, переменных, функций или классов в коде. Компилятору требуется только прототип функции или extern объявление переменной, чтобы создать объектный файл без ошибок, но компоновщик не может разрешить вызов функции или ссылку на переменную, так как код функции или переменное пространство не зарезервированы. Чтобы устранить эту проблему, обязательно Определите каждую указанную функцию и переменную в исходном файле или библиотеке, на которую вы связываетесь.

Вызов функции, который использует типы возвращаемых значений и параметров или соглашения о вызовах, которые не соответствуют объектам в определении функции. В объектных файлах C++ декорирование имен кодирует соглашение о вызовах, область класса или пространства имен, а также типы возвращаемых данных и параметров функции. Закодированная строка становится частью окончательного декорированного имени функции. Это имя используется компоновщиком для разрешения или сопоставления вызовов функции из других объектных файлов. Чтобы устранить эту проблему, убедитесь, что в объявлении функции, определении и вызовах используются одни и те же области, типы и соглашения о вызовах.

Код C++, который вызывается при включении прототипа функции в определение класса, но не включает реализацию функции. Чтобы устранить эту проблему, обязательно предоставьте определение для всех членов класса, которые вы вызываете.

Попытка вызвать чисто виртуальную функцию из абстрактного базового класса. Чистая виртуальная функция не имеет реализации базового класса. Чтобы устранить эту проблему, убедитесь, что все вызванные виртуальные функции реализованы.

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

Если это возможно, удалите вызовы функций CRT, требующих код запуска CRT. Вместо этого используйте эквиваленты Win32. Например, используйте lstrcmp вместо strcmp . Известными функциями, требующими код запуска CRT, являются некоторые функции строк и вычислений с плавающей запятой.

Проблемы согласованности

В настоящее время нет стандарта для декорирования имен C++ между поставщиками компиляторов или даже между разными версиями одного и того же компилятора. Объектные файлы, скомпилированные с разными компиляторами, могут не использовать одинаковую схему именования. Связывание их может вызвать ошибку LNK2001.

Смешивание встроенных и невстроенных параметров компиляции в разных модулях может вызвать ошибку LNK2001. Если библиотека C++ создается с включенной функцией встраивания функций (/Ob1 или /Ob2), но соответствующий заголовочный файл, описывающий функции, отключен (без inline ключевого слова), возникает эта ошибка. Чтобы устранить эту проблему, определите функции inline в файле заголовка, который включается в другие исходные файлы.

Эта ошибка может возникать, если опустить параметр LINK/NOENTRY при создании библиотеки DLL только для ресурсов. Чтобы устранить эту проблему, добавьте параметр/NOENTRY в команду Link.

Эта ошибка может возникать, если в проекте используются неверные параметры/SUBSYSTEM или/ENTRY. Например, при написании консольного приложения и задании/SUBSYSTEM: WINDOWS создается неразрешенная внешняя ошибка для WinMain . Чтобы устранить эту проблему, убедитесь, что вы соответствуете параметрам типа проекта. Дополнительные сведения об этих параметрах и точках входа см. в разделе Параметры компоновщика /SUBSYSTEM и /entry .

Ошибки экспортированного файла DEF

Эта ошибка возникает, когда экспорт, указанный в DEF-файле, не найден. Это может быть вызвано тем, что экспорт не существует, написан неправильно или использует декорированные имена C++. DEF-файл не имеет декорированных имен. Чтобы устранить эту проблему, удалите ненужные экспорты и используйте extern "C" объявления для экспортированных символов.

Использовать декорированное имя для поиска ошибки

Компилятор и компоновщик C++ используют декорирование имен, также называемое искажением имени. Декорирование имен кодирует дополнительные сведения о типе переменной в ее имени символа. Имя символа для функции кодирует свой возвращаемый тип, типы параметров, область и соглашение о вызовах. Это декорированное имя — это имя символа, которое компоновщик ищет для разрешения внешних символов.

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

Параметры /EXPORTS и /SYMBOLS программы командной строки DUMPBIN полезны здесь. Они могут помочь определить, какие символы определены в .dll и файлах объектов или библиотек. Можно использовать список символов, чтобы убедиться, что экспортированные декорированные имена соответствуют декорированным именам, которые ищет компоновщик.

В некоторых случаях Компоновщик может сообщать только о декорированном имени символа. Для получения недекорированной формы декорированного имени можно использовать программу командной строки UNDNAME.

Как говорят, «или крест снимите, или трусы наденьте». И учите понятие «единица компиляции».
По какой схеме устроен ваш проект? «Одна единица компиляции» или «много единиц компиляции»?

Си недалеко ушёл от ассемблеров. А в ассемблерах программа компилировалась по частям и собиралась воедино линкером (компоновщиком, редактором связей) — в те времена кода было много, а данных мало. Многие из ошибок невозможно было определить, не запустив линкер. Си++ пользуется многими из архитектурных особенностей ассемблеров и Си — по крайней мере ни одно из модульных решений не стало рекомендацией (кроме костыля extern template class ).

Но как говорить «переменная/функция есть, такого-то типа и в другой единице компиляции»? Для этого есть прототипы функций и extern-определения переменных. Их обычно вносят в заголовочные файлы с таким требованием: ничего, что находится в заголовочном файле, не должно производить кода. А код производят…
• Глобальные переменные (без typedef, extern).
• Нешаблонные функции (кроме inline).
• Полностью специализированные шаблонные функции (кроме inline).
• Команда «специализировать шаблон» (template class).

При этом…
• Функции в теле struct/class автоматически inline и кода не производят.
• Для неявной специализации шаблонов существуют обходы — код генерируется дважды, но ошибки не выдаёт.
• «Свой» хедер обычно включают первым, чтобы убедиться, что в нём нет недостающих зависимостей.

В системе «одна единица компиляции» всё просто: есть ровно один файл, подлежащий компиляции. Тогда в хедерных файлах вполне могут быть конструкции, производящие код.

Системы «одна единица компиляции» и «много единиц компиляции» можно комбинировать, но надо знать:
• Все хедеры, которые производят код, должны подключаться из одной-единственной единицы компиляции. Надо чётко осознавать, из какой, и не подключать из чужих.
• У библиотеки всё равно должен быть хедер-фасад, не производящий кода и предназначенный для стыковки с другими единицами компиляции.
Такая конструкция ускоряет полную перекомпиляцию и часто применяется для библиотек, но надо знать: огромные библиотеки вроде SqLite, в 5 мегабайт препроцессированного кода, мешают распараллеливанию компиляции (ибо пока откомпилируется SqLite, остальные процессоры вполне себе соберут остальную программу).

Microsoft Logo

Gray Pipe

Приносим извинения. Запрошенное содержимое было удалено. Вы будете автоматически перенаправлены через 1 секунду.

Лучший отвечающий

Вопрос

using namespace std;

void TestRussian( HFAIND hEngine );
void TestEnglish( HFAIND hEngine );

const int DEF_TIMEOUT = 1000000; // 1000 секунд

static bool exists( const TCHAR *path )


static HFAIND hEngine = NULL;
static HGREN_PHRASOMAT hFG = NULL;

sol_SetWordsForPhrase( hFG, ies.size(), &*ies.begin(), true );

static void Imitate( const wchar_t *src_filename, int language )
if( GetFileAttributesW(src_filename)==(DWORD)-1 )
return;
>

int rc = sol_BuildKnowledgeBase( hEngine, src_filename, tmp_db_folder, language, 0 );
rc = sol_LoadKnowledgeBase( hFG, tmp_db_folder );

// Free allocated resources, delete the engine instance.
sol_DeleteGrammarEngine(hEngine);


static void TestGenerator(void);
static void TestSynonymizer(void);
static void TestParaphraser(void);
static void TestImitator(void);


void TestRussian( HFAIND hEngine )
if( sol_FindEntry( hEngine, L"МАМА", /*Solarix::API::*/NOUN_ru, /*Solarix::API::*/RUSSIAN_LANGUAGE )==-1 )
cout << "Russian lexicon is missing.\n";
return;
>


TestGenerator();
TestSynonymizer();
// TestParaphraser();
TestImitator();

wchar_t buffer[10001];
memset( buffer, 0, sizeof(buffer) );

bool is_premium = sol_GetVersion( hEngine, NULL, NULL, NULL);

const wchar_t *orgs[] =
L"I decided to stay",
L"I've decided to stay",
L"We decide to stay",
L"He decides to stay",
L"I am deciding to stay",
L"You must decide to stay",
NULL
>;

int iorg=0;
while( orgs[iorg]!=NULL )
const wchar_t *s = orgs[iorg];

int rc2 = sol_Paraphrase(
hFG,
FG_SYNONYMIZE | FG_SYNONYMIZER_MULTIWORD,
FG_PEDANTIC_ANALYSIS,
FG_NO_NGRAMS,
0,
FG_DEBUG,
FG_YIELD_PLAIN_TEXT,
5,
s,
buffer,
10000,
DEF_TIMEOUT
);

const wchar_t *orgs[] =
L"I decided to stay",
L"The mouse will be surrendering",
L"The mouse is surrendering",
L"The jolly mouse", // тут ошибка!
L"The funny mouse",
L"The mouse surrendered",
L"is asked",
L"will be asked",
L"will be asking",
L"will be surrendering",
L"is surrendering",
L"The mouse surrenders",
L"The mouse will surrender",
L"Kitties",
L"Funny job",
L"Merry christmas",
L"Tremendous danger",
L"Huge disaster",
L"The mouse gives up.",
L"The kitty surrendered.",
L"White cat silently sleeps.",
L"Black cat catches the moise.",
NULL
>;

int iorg=0;
while( orgs[iorg]!=NULL )
const wchar_t *s = orgs[iorg];
int rc = sol_Paraphrase(
hFG,
FG_SYNONYMIZE | FG_SYNONYMIZER_MULTIWORD,
FG_PEDANTIC_ANALYSIS,
FG_NO_NGRAMS,
0,
FG_DEBUG,
FG_YIELD_PLAIN_TEXT,
5,
s,
buffer,
10000,
DEF_TIMEOUT
);

if( wcsstr( phrase, L"(--" )!=NULL || wcsstr( phrase, L". " )!=NULL )
printf( "Error in phrase generator!\n" );
>

я использую Visual Studio 2013. Я сделал имя решения MyProjectTest Это структура моего тестового решения:

The structure

в дереве решений Visual Studio щелкните правой кнопкой мыши на проекте "UnitTest1", затем добавьте -> существующий элемент -> выберите файл ../MyProjectTest / функция.cpp

Так как я хочу, чтобы мой проект компилировался в автономный EXE, я связал UnitTest проект с функцией.obj файл, созданный из функции.cpp и это работает. Щелкните правой кнопкой мыши на проекте 'UnitTest1' > свойства конфигурации > Компоновщик > ввод > дополнительные зависимости > добавить "..\MyProjectTest\Debug\function.obj"

оказалось, что я использовал .c файлов с .cpp-файлы. переименование. С до .cpp решил мою проблему.

другой способ, которым вы можете получить эту ошибку компоновщика (как и я), если вы экспортируете экземпляр класса из dll, но не объявили, что сам класс как импорт/экспорт.

так что, хотя в первую очередь я экспортировал только экземпляр книги класс book выше, я должен был объявить Book класс, как экспорт/импорт класса, а в противном случае вызов book.WordCount() в другой dll вызывал ошибку ссылки.

Я только что обнаружил, что LNK2019 происходит во время компиляции в Visual Studio 2015, если забыли предоставить определение для объявленной функции внутри класса.

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

для меня работает, если я добавлю эту строку ниже в .vcxproj in itemGroup cpp файл, который подключен к заголовочному файлу.

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

Проверьте набор символов обоих проектов в Свойства Конфигурации ->общие ->Набор Символов

мой UnitTest проект использовал набор символов по умолчанию Мульти-Байт в то время как мои libs где в Unicode.
Моя функция была с помощью TCHAR в качестве параметра. В результате в моей lib мой TCHAR был преобразовано на WCHAR но это char* на моем UnitTest: символ был другим, потому что параметры были действительно не то же самое в конце концов.

в Visual Studio 2017 если вы хотите протестировать общедоступные члены, просто поместите свой реальный проект и тестовый проект в одно и то же решение и добавьте ссылку на свой реальный проект в тестовом проекте.

посмотреть модульное тестирование C++ в Visual Studio из блога MSDN для получения более подробной информации. Вы также можете проверить написать модульные тесты для C / C++ в Visual Studio а также используйте платформу модульного тестирования Microsoft для C++ в Visual Studio, причем если вам нужно протестировать непубличных членов и нужно поместить тесты в тот же проект, что и ваш реальный код.

обратите внимание, что вещи, которые вы хотите протестировать должны быть экспортированы с помощью __declspec(dllexport) . Смотрите экспорт из DLL с помощью _ _ declspec (dllexport) для более подробной информации.

Читайте также: