Может ли кто-нибудь объяснить, что
__imp__fprintf
и
__imp____iob_func
неразрешенные внешние средства?
Потому что я получаю эти ошибки, когда пытаюсь скомпилировать:
1>SDL2main.lib(SDL_windows_main.obj) : error LNK2019: unresolved external symbol __imp__fprintf referenced in function _ShowError
1>SDL2main.lib(SDL_windows_main.obj) : error LNK2019: unresolved external symbol __imp____iob_func referenced in function _ShowError
1>E:\Documents\Visual Studio 2015\Projects\SDL2_Test\Debug\SDL2_Test.exe : fatal error LNK1120: 2 unresolved externals
Уже могу сказать, что проблема не в неправильной привязке. Я все связал правильно, но почему-то не компилируется.
Пытаюсь использовать SDL2.
Я использую Visual Studio 2015 в качестве компилятора.
Я связался с SDL2.lib и SDL2main.lib в Linker -> Input -> Additional Dependencies, и я убедился, что каталоги VC ++ верны.
c++
sdl-2
visual-studio-2015
unresolved-external
RockFrenzy
источник
источник
Ответы:
Я наконец понял, почему это происходит!
В Visual Studio 2015 stdin, stderr, stdout определены следующим образом:
Но раньше они определялись как:
Итак, теперь __iob_func больше не определен, что приводит к ошибке ссылки при использовании файла .lib, скомпилированного с предыдущими версиями Visual Studio.
Чтобы решить эту проблему, вы можете попробовать определить
__iob_func()
себя, который должен возвращать массив, содержащий{*stdin,*stdout,*stderr}
.Что касается других ошибок ссылок о функциях stdio (в моем случае это было
sprintf()
), вы можете добавить legacy_stdio_definitions.lib в параметры компоновщика.источник
extern "C"
в объявлении / определении.extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
Милану Бабушкову, ИМО, функция замены должна выглядеть именно так :-)
источник
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
.У Microsoft есть особое примечание по этому поводу ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):
источник
#pragma comment(lib, "legacy_stdio_definitions.lib")
- но это не исправляет__imp___iob_func
- есть ли унаследованная библиотека для этого?Как было сказано выше, правильный ответ - скомпилировать все с помощью VS2015, но для интереса ниже представлен мой анализ проблемы.
Этот символ не определен ни в одной статической библиотеке, предоставляемой Microsoft как часть VS2015, что довольно странно, как и все остальные. Чтобы понять, почему, нам нужно взглянуть на объявление этой функции и, что более важно, на то, как она используется.
Вот отрывок из заголовков Visual Studio 2008:
Итак, мы можем видеть, что задача функции - вернуть начало массива объектов FILE (не дескрипторов, «FILE *» - дескриптор, FILE - это базовая непрозрачная структура данных, хранящая важные свойства состояния). Пользователями этой функции являются три макроса stdin, stdout и stderr, которые используются для различных вызовов стилей fscanf, fprintf.
Теперь давайте посмотрим, как Visual Studio 2015 определяет те же вещи:
Таким образом, изменился подход: функция замены теперь возвращает дескриптор файла, а не адрес массива файловых объектов, а макросы изменились, чтобы просто вызывать функцию, передавая идентификационный номер.
Так почему они / мы не могут предоставить совместимый API? Есть два ключевых правила, которым Microsoft не может противоречить с точки зрения их первоначальной реализации через __iob_func:
Любое изменение в любом из вышеперечисленных будет означать, что существующий скомпилированный код, связанный с этим, будет плохо работать, если этот API будет вызван.
Давайте посмотрим, как ФАЙЛ был / определяется.
Сначала определение ФАЙЛА VS2008:
А теперь определение ФАЙЛА VS2015:
Так что в этом суть: структура изменила форму. Существующий скомпилированный код, ссылающийся на __iob_func, основан на том факте, что возвращаемые данные являются как массивом, который можно индексировать, так и тем, что в этом массиве элементы находятся на одинаковом расстоянии друг от друга.
Возможные решения, упомянутые в ответах выше в этих строках, не будут работать (если будут вызваны) по нескольким причинам:
Массив FILE _iob будет скомпилирован с VS2015, и поэтому он будет представлен как блок структур, содержащих пустоту *. При 32-битном выравнивании эти элементы будут разделены на 4 байта. Итак, _iob [0] находится со смещением 0, _iob [1] находится со смещением 4, а _iob [2] - со смещением 8. Вместо этого вызывающий код будет ожидать, что FILE будет намного длиннее, выровнен по 32 байтам в моей системе, и поэтому он возьмет адрес возвращенного массива и добавит 0 байтов, чтобы добраться до нулевого элемента (это нормально), но для _iob [1] он сделает вывод, что ему нужно добавить 32 байта, а для _iob [2] он выведет что ему нужно добавить 64 байта (потому что так это выглядело в заголовках VS2008). И действительно, дизассемблированный код VS2008 демонстрирует это.
Второстепенная проблема с вышеуказанным решением заключается в том, что оно копирует содержимое структуры FILE (* stdin), а не дескриптор FILE *. Таким образом, любой код VS2008 будет смотреть на другую базовую структуру, чем VS2015. Это могло бы сработать, если бы структура содержала только указатели, но это большой риск. В любом случае первый вопрос делает это несущественным.
Единственный хак, который мне удалось придумать, - это тот, в котором __iob_func просматривает стек вызовов, чтобы определить, какой фактический дескриптор файла они ищут (на основе смещения, добавленного к возвращаемому адресу), и возвращает вычисленное значение, чтобы оно дает правильный ответ. Это так же безумно, как кажется, но прототип только для x86 (не x64) приведен ниже для вашего развлечения. В моих экспериментах он работал нормально, но ваш опыт может отличаться - не рекомендуется для промышленного использования!
источник
У меня была такая же проблема в VS2015. Я решил это, скомпилировав исходники SDL2 в VS2015.
источник
SDL2main
и скопироватьSDL2main.lib
Не знаю почему, но:
По моему опыту, после включения, но до того, как ваш основной должен исправить это.
источник
Более новое решение этой проблемы: используйте более свежие библиотеки sdl на
" https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/?C=M;O=D "
Кажется, они устранили проблему, хотя это всего лишь 32-битная библиотека (я думаю).
источник
Ссылка означает некорректную работу. Копаясь в stdio.h VS2012 и VS2015, у меня сработало следующее. Увы, вам нужно решить, будет ли он работать для одного из {stdin, stdout, stderr}, но не более одного.
источник
Мой совет - не (пытайтесь) реализовывать __iob_func.
При исправлении этих ошибок:
libpngd.v110.lib(pngrutil.obj) : error LNK2001: unresolved external symbol ___iob_func curllib.v110.lib(mprintf.obj) : error LNK2001: unresolved external symbol ___iob_func
Я пробовал решения других ответов, но, в конце концов, возврат
FILE*
C-массива не соответствует массиву внутренних структур IOB Windows. @Volker прав в том, что он никогда не сработает более чем с одним изstdin
,stdout
илиstderr
.Если библиотека действительно ИСПОЛЬЗУЕТ один из этих потоков, произойдет сбой . Пока ваша программа не заставляет библиотеку их использовать, вы никогда не узнаете . Например,
png_default_error
записывает,stderr
когда CRC не соответствует метаданным PNG. (Обычно это не проблема, вызывающая сбой)Вывод: невозможно смешивать библиотеки VS2012 (Platform Toolset v110 / v110_xp) и VS2015 +, если они используют stdin, stdout и / или stderr.
Решение: перекомпилируйте библиотеки, в которых есть
__iob_func
неразрешенные символы, с вашей текущей версией VS и соответствующим набором инструментов платформы.источник
Используйте предварительно скомпилированные SDL2main.lib и SDL.lib для библиотеки вашего проекта VS2015: https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/sdl-visualstudio-2225.zip
источник
Я решаю эту проблему с помощью следующей функции. Я использую Visual Studio 2019.
поскольку stdin Макрос определяет вызов функции, выражение "* stdin" не может использоваться инициализатором глобального массива. Но возможен инициатор локального массива. извините, я плохо говорю по английски.
источник
Для тех, кто все еще ищет ответ, где вышеуказанные уловки не сработали. Статические ссылки - способ решить эту проблему. Измените настройки библиотеки времени выполнения, как показано ниже
Project properties --> C/C++ --> Code generation --> Runtime Library --> Multi-threaded Debug (/MTd) instead of /MDd
источник
Мне удалось исправить проблему.
Источником ошибки была эта строка кода, которую можно найти в исходном коде SDLmain.
Итак, что я сделал, так это отредактировал исходный код в SDLmain этой строки:
А затем я собрал SDLmain, скопировал и заменил старый SDLmain.lib в каталоге моей библиотеки SDL2 новым созданным и отредактированным.
Затем, когда я запустил свою программу с SDL2, сообщений об ошибках не было, и код прошел гладко.
Не знаю, укусит ли это меня потом, но так что все идет отлично.
источник
Это может произойти, если вы создадите ссылку на msvcrt.dll вместо msvcr10.dll (или аналогичную), что является хорошим планом. Потому что это освободит вас для распространения библиотеки времени выполнения Visual Studio внутри вашего окончательного программного пакета.
Этот обходной путь мне помогает (в Visual Studio 2008):
Этот фрагмент не нужен для Visual Studio 6 и его компилятора. Поэтому #ifdef.
источник
Чтобы внести больше путаницы в этот и без того богатый поток, я случайно наткнулся на тот же неразрешенный внешний вид на fprintf
Даже если в моем случае это было в совершенно другом контексте: в Visual Studio 2005 (Visual Studio 8.0) и ошибка происходила в моем собственном коде (тот самый, который я компилировал), а не в третьей стороне.
Случилось так, что эта ошибка была вызвана параметром / MD в моих флагах компилятора. Переключение на / MT устранило проблему. Это странно, потому что обычно статическое связывание (MT) вызывает больше проблем, чем динамическое (MD) ... но на всякий случай я помещаю его туда.
источник
В моем случае эта ошибка возникла из-за моего пробного удаления зависимостей от MSVC-версии зависимой библиотеки времени выполнения DLL (msvcr10.dll или около того) и / или удаления статической библиотеки времени выполнения, чтобы удалить лишний жир из моих исполняемых файлов.
Поэтому я использую переключатель компоновщика / NODEFAULTLIB, мой самодельный файл "msvcrt-light.lib" (при необходимости используйте Google) и
mainCRTStartup()
/WinMainCRTStartup()
entry.Это IMHO с Visual Studio 2015, поэтому я придерживался старых компиляторов.
Однако определение символа _NO_CRT_STDIO_INLINE устраняет все проблемы , и простое приложение «Hello World» снова имеет размер 3 КБ и не зависит от необычных DLL. Протестировано в Visual Studio 2017.
источник
Вставьте этот код в любой из ваших исходных файлов и заново соберите. Сработало у меня!
#include stdio.h
ФАЙЛ _iob [3];
ФАЙЛ * __cdecl __iob_func (void) {
_iob [0] = * стандартный ввод;
_iob [0] = * стандартный вывод;
_iob [0] = * stderr;
return _iob;
}
источник