Könnte jemand erklären was das ist
__imp__fprintf
und
__imp____iob_func
ungelöste externe Mittel?
Weil ich beim Kompilieren folgende Fehler bekomme:
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
Ich kann bereits sagen, dass das Problem nicht darin besteht, falsch zu verlinken. Ich habe alles richtig verknüpft, aber aus irgendeinem Grund wird es nicht kompiliert.
Ich versuche SDL2 zu verwenden.
Ich verwende Visual Studio 2015 als Compiler.
Ich habe unter Linker -> Eingabe -> Zusätzliche Abhängigkeiten eine Verknüpfung zu SDL2.lib und SDL2main.lib hergestellt und sichergestellt, dass die VC ++ - Verzeichnisse korrekt sind.
c++
sdl-2
visual-studio-2015
unresolved-external
RockFrenzy
quelle
quelle
Antworten:
Ich habe endlich herausgefunden, warum das passiert!
In Visual Studio 2015 werden stdin, stderr, stdout wie folgt definiert:
Zuvor wurden sie jedoch definiert als:
Jetzt ist __iob_func nicht mehr definiert, was zu einem Linkfehler führt, wenn eine .lib-Datei verwendet wird, die mit früheren Versionen von Visual Studio kompiliert wurde.
Um das Problem zu lösen, können Sie versuchen, sich
__iob_func()
selbst zu definieren, welches ein Array zurückgeben soll{*stdin,*stdout,*stderr}
.In Bezug auf die anderen Linkfehler zu stdio-Funktionen (in meinem Fall
sprintf()
) können Sie Ihren Linker-Optionen die Datei legal_stdio_definitions.lib hinzufügen .quelle
extern "C"
in der Deklaration / Definition.extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
Für Milan Babuškov, IMO, sollte die Ersatzfunktion genau so aussehen :-)
quelle
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
.Microsoft hat hierzu einen besonderen Hinweis ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):
quelle
#pragma comment(lib, "legacy_stdio_definitions.lib")
- aber das behebt das nicht__imp___iob_func
- gibt es auch dafür eine Legacy-Bibliothek?Wie oben beantwortet, ist die richtige Antwort, alles mit VS2015 zu kompilieren, aber aus Interesse ist das Folgende meine Analyse des Problems.
Dieses Symbol scheint in keiner statischen Bibliothek definiert zu sein, die von Microsoft als Teil von VS2015 bereitgestellt wird, was ziemlich eigenartig ist, da alle anderen es sind. Um herauszufinden, warum, müssen wir uns die Deklaration dieser Funktion und vor allem ihre Verwendung ansehen.
Hier ist ein Ausschnitt aus den Visual Studio 2008-Headern:
Wir können also sehen, dass die Aufgabe der Funktion darin besteht, den Anfang eines Arrays von FILE-Objekten zurückzugeben (keine Handles, "FILE *" ist das Handle, FILE ist die zugrunde liegende undurchsichtige Datenstruktur, in der die wichtigen Status-Goodies gespeichert sind). Die Benutzer dieser Funktion sind die drei Makros stdin, stdout und stderr, die für verschiedene Aufrufe im fscanf- und fprintf-Stil verwendet werden.
Schauen wir uns nun an, wie Visual Studio 2015 dieselben Dinge definiert:
Daher hat sich der Ansatz geändert, dass die Ersetzungsfunktion jetzt das Dateihandle anstelle der Adresse des Arrays von Dateiobjekten zurückgibt, und die Makros wurden geändert, um einfach die Funktion aufzurufen, die eine Identifikationsnummer übergibt.
Warum können sie / wir keine kompatible API bereitstellen? Es gibt zwei wichtige Regeln, gegen die Microsoft bei der ursprünglichen Implementierung über __iob_func nicht verstoßen kann:
Jede Änderung in einem der oben genannten Punkte würde bedeuten, dass vorhandener kompilierter Code, der mit diesem verknüpft ist, beim Aufruf dieser API schlecht funktioniert.
Werfen wir einen Blick darauf, wie FILE definiert wurde / wird.
Zuerst die VS2008-DATEI-Definition:
Und jetzt die Definition der VS2015-DATEI:
Da ist also der springende Punkt: Die Struktur hat ihre Form geändert. Vorhandener kompilierter Code, der sich auf __iob_func bezieht, beruht auf der Tatsache, dass die zurückgegebenen Daten sowohl ein Array sind, das indiziert werden kann, als auch dass die Elemente in diesem Array den gleichen Abstand voneinander haben.
Die möglichen Lösungen, die in den obigen Antworten in diesem Sinne erwähnt werden, würden aus einigen Gründen nicht funktionieren (wenn sie aufgerufen werden):
Das FILE-Array _iob würde mit VS2015 kompiliert und daher als Strukturblock mit einer Leere * angelegt. Unter der Annahme einer 32-Bit-Ausrichtung wären diese Elemente 4 Byte voneinander entfernt. Also ist _iob [0] auf Offset 0, _iob [1] auf Offset 4 und _iob [2] auf Offset 8. Der aufrufende Code erwartet stattdessen, dass FILE viel länger ist und auf meinem System mit 32 Bytes ausgerichtet ist, und so weiter Es nimmt die Adresse des zurückgegebenen Arrays und addiert 0 Bytes, um zum Element Null zu gelangen (dieses ist in Ordnung), aber für _iob [1] wird abgeleitet, dass 32 Bytes hinzugefügt werden müssen, und für _iob [2] wird abgeleitet dass es 64 Bytes hinzufügen muss (weil es in den VS2008-Headern so aussah). Und tatsächlich zeigt der zerlegte Code für VS2008 dies.
Ein sekundäres Problem bei der obigen Lösung besteht darin, dass der Inhalt der FILE-Struktur (* stdin) kopiert wird , nicht das FILE * -Handle. Jeder VS2008-Code würde also eine andere zugrunde liegende Struktur als VS2015 betrachten. Dies könnte funktionieren, wenn die Struktur nur Zeiger enthält, aber das ist ein großes Risiko. In jedem Fall macht die erste Ausgabe dies irrelevant.
Der einzige Hack, den ich mir ausdenken konnte, ist ein Hack, bei dem __iob_func den Aufrufstapel durchläuft, um herauszufinden, nach welchem tatsächlichen Dateihandle sie suchen (basierend auf dem Offset, der der zurückgegebenen Adresse hinzugefügt wurde), und einen berechneten Wert zurückgibt, so dass dieser gibt die richtige Antwort. Dies ist genauso verrückt wie es sich anhört, aber der Prototyp nur für x86 (nicht x64) ist unten aufgeführt, um Sie zu unterhalten. In meinen Experimenten hat es gut funktioniert, aber Ihr Kilometerstand kann variieren - nicht für den Produktionsbetrieb empfohlen!
quelle
Ich hatte das gleiche Problem in VS2015. Ich habe es gelöst, indem ich die SDL2-Quellen in VS2015 kompiliert habe.
quelle
SDL2main
überSDL2main.lib
Ich weiß nicht warum, aber:
Nach den Includes, aber bevor Ihr Main es aus meiner Erfahrung beheben sollte.
quelle
Eine neuere Lösung für dieses Problem: Verwenden Sie die neueren SDL-Bibliotheken
" https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/?C=M;O=D "
Sie scheinen das Problem behoben zu haben, obwohl es nur die 32-Bit-Bibliothek ist (glaube ich).
quelle
Verknüpfen bedeutet, nicht richtig zu arbeiten. Das Stöbern in stdio.h von VS2012 und VS2015 hat für mich funktioniert. Leider müssen Sie entscheiden, ob es für einen von {stdin, stdout, stderr} funktionieren soll, niemals mehr als einen.
quelle
Mein Rat ist, __iob_func nicht zu implementieren.
Während der Behebung dieser Fehler:
libpngd.v110.lib(pngrutil.obj) : error LNK2001: unresolved external symbol ___iob_func curllib.v110.lib(mprintf.obj) : error LNK2001: unresolved external symbol ___iob_func
Ich habe die Lösungen der anderen Antworten ausprobiert, aber am Ende
FILE*
stimmt die Rückgabe eines C-Arrays nicht mit einem Array der internen IOB-Strukturen von Windows überein. @Volker ist richtig , dass es werde nie Arbeit für mehr als einestdin
,stdout
oderstderr
.Wenn eine Bibliothek tatsächlich einen dieser Streams verwendet, stürzt sie ab . Solange Ihr Programm nicht bewirkt, dass die Bibliothek sie verwendet, werden Sie es nie erfahren .
png_default_error
Schreibt beispielsweise,stderr
wenn der CRC nicht mit den Metadaten des PNG übereinstimmt. (Normalerweise kein absturzwürdiges Problem)Schlussfolgerung: Es ist nicht möglich, die Bibliotheken VS2012 (Platform Toolset v110 / v110_xp) und VS2015 + zu mischen, wenn sie stdin, stdout und / oder stderr verwenden.
Lösung: Kompilieren Sie Ihre Bibliotheken mit
__iob_func
nicht aufgelösten Symbolen mit Ihrer aktuellen Version von VS und einem passenden Platform Toolset neu.quelle
Verwenden Sie die vorkompilierte Datei SDL2main.lib und SDL.lib für die Bibliothek Ihres VS2015-Projekts: https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/sdl-visualstudio-2225.zip
quelle
Ich löse dieses Problem mit der folgenden Funktion. Ich benutze Visual Studio 2019.
Da der Funktionsaufruf stdin Macro definiert ist, kann der Ausdruck "* stdin" nicht als globaler Array-Initialisierer verwendet werden. Ein lokaler Array-Initialisierer ist jedoch möglich. Entschuldigung, ich bin schlecht in Englisch.
quelle
Für alle, die noch nach einer Antwort suchen, bei der die oben genannten Tricks nicht funktioniert haben. Durch statische Verknüpfung kann dieses Problem gelöst werden. Ändern Sie die Einstellungen Ihrer Runtime-Bibliothek wie folgt
Project properties --> C/C++ --> Code generation --> Runtime Library --> Multi-threaded Debug (/MTd) instead of /MDd
quelle
Ich habe es geschafft, das Problem zu beheben.
Die Fehlerquelle war diese Codezeile, die im SDLmain-Quellcode enthalten ist.
Also habe ich auch den Quellcode in SDLmain dieser Zeile bearbeitet:
Und dann habe ich die SDLmain erstellt und die alte SDLmain.lib in meinem SDL2-Bibliotheksverzeichnis kopiert und durch die neu erstellte und bearbeitete ersetzt.
Als ich dann mein Programm mit SDL2 ausführte, traten keine Fehlermeldungen auf und der Code lief reibungslos.
Ich weiß nicht, ob mich das später beißen wird, aber alles läuft großartig.
quelle
Dies kann passieren, wenn Sie eine Verknüpfung zu msvcrt.dll anstelle von msvcr10.dll (oder ähnlichem) herstellen. Dies ist ein guter Plan. Dadurch können Sie die Laufzeitbibliothek Ihres Visual Studios in Ihrem endgültigen Softwarepaket neu verteilen.
Diese Problemumgehung hilft mir (bei Visual Studio 2008):
Dieses Snippet wird für Visual Studio 6 und seinen Compiler nicht benötigt. Daher das #ifdef.
quelle
Um mehr Verwirrung in diesem bereits reichhaltigen Thread zu stiften, bin ich zufällig auf fprintf auf dasselbe ungelöste externe Element gestoßen
Auch wenn es in meinem Fall in einem anderen Kontext war: Unter Visual Studio 2005 (Visual Studio 8.0) trat der Fehler in meinem eigenen Code auf (genau dem, den ich kompiliert habe), nicht in einem Drittanbieter.
Es ist passiert, dass dieser Fehler durch die Option / MD in meinen Compiler-Flags ausgelöst wurde. Durch Umschalten auf / MT wurde das Problem behoben. Das ist seltsam, weil das statische Verknüpfen (MT) normalerweise mehr Probleme aufwirft als das dynamische (MD) ... aber nur für den Fall, dass es anderen dient, habe ich es dort abgelegt.
quelle
In meinem Fall stammt dieser Fehler aus meiner Testversion zum Entfernen von Abhängigkeiten zur von der MSVC-Version abhängigen Laufzeitbibliotheks-DLL (msvcr10.dll oder so) und / oder zum Entfernen der statischen Laufzeitbibliothek, um überschüssiges Fett aus meinen ausführbaren Dateien zu entfernen.
Also benutze ich den Linker-Schalter / NODEFAULTLIB, meine selbst erstellte "msvcrt-light.lib" (bei Bedarf googeln) und
mainCRTStartup()
/WinMainCRTStartup()
Einträge.Es ist IMHO seit Visual Studio 2015, also habe ich mich an ältere Compiler gehalten.
Das Definieren des Symbols _NO_CRT_STDIO_INLINE beseitigt jedoch jeglichen Aufwand, und eine einfache "Hello World" -Anwendung ist wieder 3 KB klein und hängt nicht von ungewöhnlichen DLLs ab. Getestet in Visual Studio 2017.
quelle
Fügen Sie diesen Code in eine Ihrer Quelldateien ein und erstellen Sie ihn neu. Hat für mich gearbeitet!
#include stdio.h
DATEI _iob [3];
DATEI * __cdecl __iob_func (void) {
_iob [0] = * stdin;
_iob [0] = * stdout;
_iob [0] = * stderr;
return _iob;
}}
quelle