ungelöstes externes Symbol __imp__fprintf und __imp____iob_func, SDL2

108

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.

RockFrenzy
quelle
1
Könnten Sie dies beweisen, indem Sie bitte Ihre Linker-Einstellungen anzeigen.
πάντα ῥεῖ
@ πάνταῥεῖ, ich habe in den Eingabe-Linker-Einstellungen eine Verknüpfung zu SDL2.lib und SDL2main.lib hergestellt und sichergestellt, dass die Verzeichnisse auf das richtige Verzeichnis verweisen.
RockFrenzy
1
Mögliches Duplikat des Fehlers LNK2001 __imp_fprintf Visual Studio 2015 RC
entwaffnet

Antworten:

123

Ich habe endlich herausgefunden, warum das passiert!

In Visual Studio 2015 werden stdin, stderr, stdout wie folgt definiert:

#define stdin  (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))

Zuvor wurden sie jedoch definiert als:

#define stdin  (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])

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 .

Gott
quelle
1
Vielen Dank, dass Sie dies aufgespürt haben. IIRC Das Problem mit {* stdin, * stdout, * stderr} könnte sein, dass verschiedene Kompilierungseinheiten möglicherweise eine 'eigene' Kopie von stdin haben, weshalb diese Funktionen direkt aufgerufen wurden.
Steven R. Loomis
3
das löste sich auch für mich, nur eine Erinnerung zur Verwendung extern "C"in der Deklaration / Definition.
Vargas
4
Kann jemand genau schreiben, wie die Ersatzfunktion aussehen soll? Ich habe verschiedene Varianten ausprobiert und bekomme immer wieder Kompilierungsfehler. Vielen Dank.
Milan Babuškov
55
extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
PoL0
1
Die obige Definition von iob_func funktioniert nicht. Eine korrekte Definition finden Sie in der Antwort von MarkH. (Sie können nicht einfach eine Funktion als Array definieren und erwarten, dass Aufrufe funktionieren.)
Hans Olsson
59

Für Milan Babuškov, IMO, sollte die Ersatzfunktion genau so aussehen :-)

FILE _iob[] = {*stdin, *stdout, *stderr};

extern "C" FILE * __cdecl __iob_func(void)
{
    return _iob;
}
smartsl
quelle
5
Ich vermisse nur ein #ifdef für MSVC und für MSVC Version <2015
Paulm
1
Wie MarkH in einer anderen Antwort feststellt, sieht das richtig aus, funktioniert aber nicht.
Hans Olsson
4
@ Paulm Ich denke du meinst #if defined(_MSC_VER) && (_MSC_VER >= 1900).
Jesse Chisholm
@ JesseChisholm hängt vielleicht davon ab, ob dies auch für jede bekannte zukünftige Version von MSVC gilt oder nicht;)
Paulm
42

Microsoft hat hierzu einen besonderen Hinweis ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):

Die Funktionsfamilie printf und scanf wird jetzt inline definiert.

Die Definitionen aller Funktionen printf und scanf wurden inline in stdio.h , conio.h und andere CRT-Header verschoben . Dies ist eine wichtige Änderung, die zu einem Linkerfehler (LNK2019, ungelöstes externes Symbol) für alle Programme führt, die diese Funktionen lokal deklariert haben, ohne die entsprechenden CRT-Header einzuschließen. Wenn möglich, sollten Sie den Code so aktualisieren, dass er die CRT-Header (dh #include) und die Inline-Funktionen enthält. Wenn Sie Ihren Code jedoch nicht so ändern möchten, dass er diese Header-Dateien enthält, können Sie alternativ eine zusätzliche Lösung hinzufügen Bibliothek zu Ihrer Linker-Eingabe, legal_stdio_definitions.lib .

Um diese Bibliothek zu Ihrer Linker-Eingabe in der IDE hinzuzufügen, öffnen Sie das Kontextmenü für den Projektknoten, wählen Sie Eigenschaften, wählen Sie dann im Dialogfeld Projekteigenschaften die Option Linker und bearbeiten Sie die Linker-Eingabe, um dem Semikolon die Datei Legacy_stdio_definitions.lib hinzuzufügen -getrennte Liste.

Wenn Ihr Projekt mit statischen Bibliotheken verknüpft ist, die mit einer Version von Visual C ++ vor 2015 kompiliert wurden, meldet der Linker möglicherweise ein ungelöstes externes Symbol. Diese Fehler können auf interne stdio-Definitionen für _iob , _iob_func oder verwandte Importe für bestimmte stdio-Funktionen in Form von __imp_ * verweisen.. Microsoft empfiehlt, dass Sie beim Aktualisieren eines Projekts alle statischen Bibliotheken mit der neuesten Version des Visual C ++ - Compilers und der Bibliotheken neu kompilieren. Wenn es sich bei der Bibliothek um eine Bibliothek eines Drittanbieters handelt, für die keine Quelle verfügbar ist, sollten Sie entweder eine aktualisierte Binärdatei vom Drittanbieter anfordern oder Ihre Verwendung dieser Bibliothek in einer separaten DLL kapseln, die Sie mit der älteren Version des Visual C ++ - Compilers kompilieren und Bibliotheken.

Königeb
quelle
7
Oder #pragma comment(lib, "legacy_stdio_definitions.lib")- aber das behebt das nicht __imp___iob_func- gibt es auch dafür eine Legacy-Bibliothek?
Bytecode77
29

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:

_CRTIMP FILE * __cdecl __iob_func(void);
#define stdin (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])

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:

_ACRTIMP_ALT FILE* __cdecl __acrt_iob_func(unsigned);
#define stdin (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))

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:

  1. Es muss ein Array von drei FILE-Strukturen vorhanden sein, die auf die gleiche Weise wie zuvor indiziert werden können.
  2. Das strukturelle Layout von FILE kann sich nicht ändern.

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:

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;

Und jetzt die Definition der VS2015-DATEI:

typedef struct _iobuf
{
    void* _Placeholder;
} FILE;

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):

FILE _iob[] = {*stdin, *stdout, *stderr};

extern "C" FILE * __cdecl __iob_func(void)
{
    return _iob;
}

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!

#include <windows.h>
#include <stdio.h>
#include <dbghelp.h>

/* #define LOG */

#if defined(_M_IX86)

#define GET_CURRENT_CONTEXT(c, contextFlags) \
  do { \
    c.ContextFlags = contextFlags; \
    __asm    call x \
    __asm x: pop eax \
    __asm    mov c.Eip, eax \
    __asm    mov c.Ebp, ebp \
    __asm    mov c.Esp, esp \
  } while(0);

#else

/* This should work for 64-bit apps, but doesn't */
#define GET_CURRENT_CONTEXT(c, contextFlags) \
  do { \
    c.ContextFlags = contextFlags; \
    RtlCaptureContext(&c); \
} while(0);

#endif

FILE * __cdecl __iob_func(void)
{
    CONTEXT c = { 0 };
    STACKFRAME64 s = { 0 };
    DWORD imageType;
    HANDLE hThread = GetCurrentThread();
    HANDLE hProcess = GetCurrentProcess();

    GET_CURRENT_CONTEXT(c, CONTEXT_FULL);

#ifdef _M_IX86
    imageType = IMAGE_FILE_MACHINE_I386;
    s.AddrPC.Offset = c.Eip;
    s.AddrPC.Mode = AddrModeFlat;
    s.AddrFrame.Offset = c.Ebp;
    s.AddrFrame.Mode = AddrModeFlat;
    s.AddrStack.Offset = c.Esp;
    s.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
    imageType = IMAGE_FILE_MACHINE_AMD64;
    s.AddrPC.Offset = c.Rip;
    s.AddrPC.Mode = AddrModeFlat;
    s.AddrFrame.Offset = c.Rsp;
    s.AddrFrame.Mode = AddrModeFlat;
    s.AddrStack.Offset = c.Rsp;
    s.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
    imageType = IMAGE_FILE_MACHINE_IA64;
    s.AddrPC.Offset = c.StIIP;
    s.AddrPC.Mode = AddrModeFlat;
    s.AddrFrame.Offset = c.IntSp;
    s.AddrFrame.Mode = AddrModeFlat;
    s.AddrBStore.Offset = c.RsBSP;
    s.AddrBStore.Mode = AddrModeFlat;
    s.AddrStack.Offset = c.IntSp;
    s.AddrStack.Mode = AddrModeFlat;
#else
#error "Platform not supported!"
#endif

    if (!StackWalk64(imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
    {
#ifdef LOG
        printf("Error: 0x%08X (Address: %p)\n", GetLastError(), (LPVOID)s.AddrPC.Offset);
#endif
        return NULL;
    }

    if (s.AddrReturn.Offset == 0)
    {
        return NULL;
    }

    {
        unsigned char const * assembly = (unsigned char const *)(s.AddrReturn.Offset);
#ifdef LOG
        printf("Code bytes proceeding call to __iob_func: %p: %02X,%02X,%02X\n", assembly, *assembly, *(assembly + 1), *(assembly + 2));
#endif
        if (*assembly == 0x83 && *(assembly + 1) == 0xC0 && (*(assembly + 2) == 0x20 || *(assembly + 2) == 0x40))
        {
            if (*(assembly + 2) == 32)
            {
                return (FILE*)((unsigned char *)stdout - 32);
            }
            if (*(assembly + 2) == 64)
            {
                return (FILE*)((unsigned char *)stderr - 64);
            }

        }
        else
        {
            return stdin;
        }
    }
    return NULL;
}
MarkH
quelle
Die richtige Antwort lautet: Die einfachste Lösung besteht darin, das Projekt auf VS2015 zu aktualisieren und dann zu kompilieren.
Akumaburn
2
In meinem Fall muss ich viele Projekte (C ++ - und C # -Projekte) von Visual Studio 2013 aktualisieren, um Visual Studio 2015 Update 3 verwenden zu können. Ich möchte VC100 (Visual Studio 2010 C ++ - Compiler) beim Erstellen von C ++ - Projekten beibehalten, habe jedoch dieselben Fehler wie oben. Ich habe imp _fprintf behoben , indem ich dem Linker Legacy_stdio_definitions.lib hinzugefügt habe . Wie kann ich auch _imp____iob_func reparieren ?
Mohamed BOUZIDI
Ist es normal, dass diese Fehler auftreten, wenn Sie msbuild 14 und IntelCompiler 2016 und VC100 zum Kompilieren von C ++ - Projekten verwenden, bevor Sie meine vorherige Frage beantworten?
Mohamed BOUZIDI
1
Was kann ich für eine x64-Kompilierung tun?
Athos
28

Ich hatte das gleiche Problem in VS2015. Ich habe es gelöst, indem ich die SDL2-Quellen in VS2015 kompiliert habe.

  1. Gehen Sie zu http://libsdl.org/download-2.0.php und laden Sie den SDL 2-Quellcode herunter.
  2. Öffnen Sie SDL_VS2013.sln in VS2015 . Sie werden aufgefordert, die Projekte zu konvertieren. Tu es.
  3. Kompilieren Sie das SDL2-Projekt.
  4. Kompilieren Sie das SDL2main-Projekt.
  5. Verwenden Sie die neu generierten Ausgabedateien SDL2main.lib, SDL2.lib und SDL2.dll in Ihrem SDL 2-Projekt in VS2015.

quelle
4
Übrigens erfordert das Erstellen von SDL 2.0.3 die Installation des DirectX SDK vom Juni 2010.
Joe
1
Hat für mich gearbeitet, danke !! Aber ich musste nur SDL2mainüberSDL2main.lib
kgwong
10

Ich weiß nicht warum, aber:

#ifdef main
#undef main
#endif

Nach den Includes, aber bevor Ihr Main es aus meiner Erfahrung beheben sollte.

Das XGood
quelle
1
.... Okay .... bevor ich das versuchte, sagte ich mir hörbar, dass ich irgendwie bezweifle, dass dies funktionieren wird, aber es hat total funktioniert ..... kannst du erklären, warum das funktioniert ...?
Trevor Hart
1
@TrevorHart Ich glaube, dass es eine "fehlerhafte" SDL- Hauptdefinition enthält , die Verweise auf die "undefinierten" Puffer enthält, und wenn Ihre Ihre Puffer verwendet, dann funktioniert alles gut und gut.
Die XGood
2
Das sind schreckliche Hacks für schlechte Übungen, aber es sind 3 Zeilen und es funktioniert und es hat mich davon abgehalten, ein Kaninchenloch zu bauen, um SDL so ... gut gemacht zu machen.
Cheezmeister
1
@Cheezmeister Schlechte Übung und Hacks sind oft für alles erforderlich. Besonders die Dinge, die sie nicht brauchen sollten.
Die XGood
7

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.

extern "C" FILE* __cdecl __iob_func()
{
    struct _iobuf_VS2012 { // ...\Microsoft Visual Studio 11.0\VC\include\stdio.h #56
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname; };
    // VS2015 has only FILE = struct {void*}

    int const count = sizeof(_iobuf_VS2012) / sizeof(FILE);

    //// stdout
    //return (FILE*)(&(__acrt_iob_func(1)->_Placeholder) - count);

    // stderr
    return (FILE*)(&(__acrt_iob_func(2)->_Placeholder) - 2 * count);
}
Volker
quelle
7

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 eine stdin, stdoutoder stderr.

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_errorSchreibt beispielsweise, stderrwenn 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_funcnicht aufgelösten Symbolen mit Ihrer aktuellen Version von VS und einem passenden Platform Toolset neu.

Luc Bloom
quelle
2

Ich löse dieses Problem mit der folgenden Funktion. Ich benutze Visual Studio 2019.

FILE* __cdecl __iob_func(void)
{
    FILE _iob[] = { *stdin, *stdout, *stderr };
    return _iob;
}

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.

soen.kr
quelle
1

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

Sisir
quelle
Hier ist eine Diskussion über diese Lösung: social.msdn.microsoft.com/Forums/vstudio/en-US/…
Sisir
0

Ich habe es geschafft, das Problem zu beheben.

Die Fehlerquelle war diese Codezeile, die im SDLmain-Quellcode enthalten ist.

fprintf(stderr, "%s: %s\n", title, message);

Also habe ich auch den Quellcode in SDLmain dieser Zeile bearbeitet:

fprintf("%s: %s\n", title, message);

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.

RockFrenzy
quelle
Ihre Änderung ist an und für sich ein Fehler und hätte das in Ihrer Frage beschriebene Problem nicht behoben. Es ist nur ein Zufall, dass Sie keine Linkerfehler mehr erhalten. Dies ist wahrscheinlich nur das Ergebnis der Neuerstellung der Bibliothek.
Ross Ridge
@ RossRidge, oh ja, das könnte einfach so gewesen sein. Ah, gut.
RockFrenzy
0

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):

#if _MSC_VER >= 1400
#undef stdin
#undef stdout
#undef stderr
extern "C" _CRTIMP extern FILE _iob[];
#define stdin   _iob
#define stdout  (_iob+1)
#define stderr  (_iob+2)
#endif

Dieses Snippet wird für Visual Studio 6 und seinen Compiler nicht benötigt. Daher das #ifdef.

user2699548
quelle
0

Um mehr Verwirrung in diesem bereits reichhaltigen Thread zu stiften, bin ich zufällig auf fprintf auf dasselbe ungelöste externe Element gestoßen

main.obj : error LNK2019: unresolved external symbol __imp__fprintf referenced in function _GenerateInfoFile

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.

Zzirkonium
quelle
0

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.

Henrik Haftmann
quelle
-2

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;

}}

Deep Patel
quelle
Sie sollten die Formatierung mit `` `und auch einige Erklärungen hinzufügen
Antonin GAVREL
Während dieser Code die Frage lösen kann, einschließlich einer Erklärung, wie und warum dies das Problem löst, würde dies wirklich dazu beitragen, die Qualität Ihres Beitrags zu verbessern, und wahrscheinlich zu mehr Up-Votes führen. Denken Sie daran, dass Sie in Zukunft die Frage für die Leser beantworten, nicht nur für die Person, die jetzt fragt. Bitte bearbeiten Sie Ihre Antwort, um Erklärungen hinzuzufügen und anzugeben, welche Einschränkungen und Annahmen gelten.
Brian