symbol zewnętrzny imp fprintf i Imp IOB func, SDL2

Mógłby ktoś wyjaśnić, co

_ _ imp_ _ fprintf

I

_ _ imp_ _ _ IOB _ func

Nierozwiązane zewnętrzne środki?

Ponieważ dostaję te błędy, gdy próbuję skompilować:

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

Mogę już powiedzieć, że problem nie polega na błędnym łączeniu. Połączyłem wszystko poprawnie, ale z jakiegoś powodu nie będzie się kompilować.

Próbuję użyć SDL2. Używam Visual Studio 2015 jako kompilator.

Połączyłem się z SDL2.lib i SDL2main.lib w Linker - > Input - > Additional Dependencies i upewniłem się, że katalogi VC++ są poprawne.

Author: RockFrenzy, 2015-05-23

12 answers

W końcu zrozumiałem, dlaczego tak się dzieje !

W visual studio 2015 stdin, stderr, stdout są zdefiniowane następująco:
#define stdin  (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))

Ale wcześniej definiowano je jako:

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

Więc teraz _ _ IOB _ func nie jest już zdefiniowany, co prowadzi do błędu łącza podczas używania .plik LIB skompilowany z poprzednimi wersjami visual studio.

Aby rozwiązać problem, możesz samodzielnie zdefiniować __iob_func(), która powinna zwrócić tablicę zawierającą {*stdin,*stdout,*stderr}.

Odnośnie drugiej błędy linkowania dotyczące funkcji stdio( w moim przypadku było to sprintf()), można dodać legacy_stdio_definitions.lib do opcji linkera.

 99
Author: god,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-17 14:20:15

Do Milana Babuškova, IMO tak powinna wyglądać funkcja zastępcza: -)

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

extern "C" FILE * __cdecl __iob_func(void)
{
    return _iob;
}
 45
Author: smartsl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-08 04:33:41

Microsoft ma specjalną notkę na ten temat ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT):

Rodziny funkcji printf i scanf są teraz definiowane inline.

Definicje wszystkich funkcji printf i scanf zostały przeniesione inline do stdio.h, conio.h i inne nagłówki CRT. Jest to przełomowa zmiana, która prowadzi do błędu linkera (lnk2019, nierozwiązany symbol zewnętrzny) dla wszystkich programów, które zadeklarowały te działa lokalnie bez włączania odpowiednich nagłówków CRT. Jeśli to możliwe, powinieneś zaktualizować kod, aby zawierał nagłówki CRT (tj. dodaj #include ) i funkcje wbudowane, ale jeśli nie chcesz modyfikować kodu, aby zawierał te pliki nagłówkowe, alternatywnym rozwiązaniem jest dodanie dodatkowej biblioteki do wejścia linkera, legacy_stdio_definitions.lib .

Aby dodać tę bibliotekę do swojego linkera w IDE, otwórz menu kontekstowe dla węzła projektu, wybierz Właściwości, następnie w oknie dialogowym Właściwości projektu wybierz łącznik i edytuj wejście łącznika, aby dodać legacy_stdio_definitions.lib do listy rozdzielonej dwukropkiem.

Jeśli twój projekt łączy się ze statycznymi bibliotekami, które zostały skompilowane z wydaniem Visual C++ wcześniej niż 2015, linker może zgłosić nierozwiązany symbol zewnętrzny. Błędy te mogą odwoływać się do wewnętrznych definicji stdio dla _iob, _iob_func , lub pokrewnych importów dla niektórych funkcji stdio w postaci of _ _ imp_ * . Microsoft zaleca przekompilowanie wszystkich bibliotek statycznych przy użyciu najnowszej wersji kompilatora i bibliotek Visual C++ podczas aktualizacji projektu. Jeśli Biblioteka jest biblioteką innej firmy, dla której źródło nie jest dostępne, należy albo zażądać zaktualizowanego pliku binarnego od strony trzeciej lub zamknąć użycie tej biblioteki w oddzielnej bibliotece DLL, którą kompilujesz ze starszą wersją kompilatora i bibliotek Visual C++.

 31
Author: kingsb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-26 15:48:41

Miałem ten sam problem w VS2015. Rozwiązałem to kompilując źródła SDL2 w VS2015.

  1. Idź do http://libsdl.org/download-2.0.php i pobierz kod źródłowy SDL 2.
  2. Otwórz SDL_VS2013.sln in VS2015 . Zostaniesz poproszony o konwersję projektów. Zrób to.
  3. skompilować projekt SDL2.
  4. skompilować projekt SDL2main.
  5. Użyj nowo wygenerowanych plików wyjściowych SDL2main.lib, SDL2.lib i SDL2.dll w projekcie SDL 2 w VS2015.
 27
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-26 16:36:14

Jak odpowiedziano powyżej, właściwą odpowiedzią jest skompilowanie wszystkiego za pomocą VS2015, ale dla zainteresowania poniżej znajduje się moja analiza problemu.

Symbol ten nie wydaje się być zdefiniowany w żadnej statycznej bibliotece dostarczonej przez Microsoft jako część VS2015, co jest dość osobliwe, ponieważ wszystkie inne są. Aby dowiedzieć się dlaczego, musimy przyjrzeć się deklaracji tej funkcji i, co ważniejsze, jak jest ona używana.

Oto fragment nagłówków Visual Studio 2008:
_CRTIMP FILE * __cdecl __iob_func(void);
#define stdin (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])

Więc widzimy, że zadaniem funkcji jest zwrócenie początku tablicy obiektów plików (nie uchwyty, "plik *" jest uchwytem, plik jest podstawową nieprzezroczystą strukturą danych przechowującą ważne gadżety stanu). Użytkownikami tej funkcji są trzy makra stdin, stdout i stderr, które są używane do różnych wywołań stylów fscanf, fprintf.

Przyjrzyjmy się teraz, jak Visual Studio 2015 definiuje te same rzeczy:]}
_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))

Więc podejście zmieniło się dla zastąpienia funkcja zwraca teraz Uchwyt Pliku, a nie adres tablicy obiektów plików, a makra zostały zmienione, aby po prostu wywołać funkcję przekazującą numer identyfikacyjny.

Więc dlaczego oni/my nie możemy zapewnić kompatybilnego API? Istnieją dwie kluczowe reguły, których Microsoft nie może złamać pod względem pierwotnej implementacji za pomocą __IOB_func:

  1. musi istnieć tablica trzech struktur plików, które mogą być indeksowane w taki sam sposób jak poprzednio.
  2. The układ strukturalny pliku nie może się zmienić.

Jakakolwiek zmiana w którymkolwiek z powyższych znaczyłaby, że istniejący skompilowany kod powiązany z tym byłby źle wywołany, gdyby to API zostało wywołane.

Przyjrzyjmy się, jak plik był/jest zdefiniowany.

Najpierw definicja pliku VS2008:

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

A teraz definicja pliku VS2015:

typedef struct _iobuf
{
    void* _Placeholder;
} FILE;

Więc jest sedno tego: struktura zmieniła kształt. Istniejący skompilowany kod odwołujący się do _ _ IOB_func polega na tym, że zwracane dane są zarówno tablicą, która może być indeksowana, jak i że w tej tablicy elementy są w tej samej odległości od siebie.

Możliwe rozwiązania wymienione w odpowiedziach powyżej w tym zakresie nie będą działać (jeśli zostaną wywołane) z kilku powodów:

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

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

Tablica plików _iob zostanie skompilowana z VS2015, a więc będzie rozplanowana jako blok struktur zawierających pustkę*. Zakładając 32-bitowe wyrównanie, elementy te byłyby oddalone od siebie o 4 bajty. Więc _iob[0] jest na offsecie 0, _iob[1] jest na offset 4 i _iob[2] znajduje się na offsecie 8. Zamiast tego Kod wywoławczy będzie oczekiwał, że plik będzie znacznie dłuższy, wyrównany do 32 bajtów w moim systemie, więc będzie pobierał adres zwracanej tablicy i dodawał 0 bajtów, aby dostać się do elementu zero (ten jest w porządku), ale dla _iob[1] wydedukował, że musi dodać 32 bajty, a dla _iob[2] wydedukował, że musi dodać 64 bajty (ponieważ tak to wyglądało w nagłówkach VS2008). I rzeczywiście demontowany kod VS2008 to pokazuje.

A drugi problem z powyższym rozwiązaniem polega na tym, że kopiuje zawartość struktury pliku (*stdin), a nie Plik * handle. Więc każdy kod VS2008 będzie patrzył na inną strukturę bazową niż VS2015. Może to zadziałać, jeśli struktura zawiera tylko wskaźniki, ale jest to duże ryzyko. W każdym razie pierwsza kwestia sprawia, że jest to nieistotne.

Jedynym hackiem, który udało mi się wymyślić, jest ten, w którym_ _ IOB _ func chodzi po stosie połączeń, aby dowiedzieć się, który plik obsługuje poszukuje (na podstawie przesunięcia dodanego do zwracanego adresu) i zwraca obliczoną wartość tak, że daje prawidłową odpowiedź. To jest tak szalone, Jak to brzmi, ale prototyp tylko dla x86 (nie x64) jest wymieniony poniżej dla Twojej rozrywki. W moich eksperymentach działało dobrze, ale twój przebieg może się różnić - nie jest zalecany do użytku produkcyjnego!

#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;
}
 20
Author: MarkH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-07 12:32:18

Nie wiem dlaczego ale:

#ifdef main
#undef main
#endif

Po includes ale przed głównym powinien to naprawić z mojego doświadczenia.

 7
Author: The XGood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-11 02:25:34

Nowsze rozwiązanie tego problemu: użyj nowszych bibliotek sdl na

"https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/?C=M;O = D "

Wydaje się, że naprawili problem, chociaż to tylko Biblioteka 32 bitowa (tak myślę).

 6
Author: Vhaerun Of Decrepitude,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-08 19:43:54

Aby link znaczy nie działać poprawnie. Kopanie w stdio.h z VS2012 i VS2015 zadziałało dla mnie. Niestety, musisz zdecydować, czy powinno działać dla jednego z { stdin, stdout, stderr}, nigdy więcej niż jednego.

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);
}
 5
Author: Volker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-02 13:36:58

Radzę nie (próbować) implementować_ _ IOB _ func.

Podczas naprawiania tych błędów:

libpngd.v110.lib(pngrutil.obj) : error LNK2001: unresolved external symbol ___iob_func curllib.v110.lib(mprintf.obj) : error LNK2001: unresolved external symbol ___iob_func

Próbowałem innych rozwiązań odpowiedzi, ale ostatecznie zwracanie FILE* tablicy C nie pasuje do tablicy wewnętrznych struktur IOB systemu Windows. @Volker ma rację, że to nigdy nie zadziała dla więcej niż jednego z stdin, stdout lub stderr.

Jeśli Biblioteka faktycznie użyje jednego z tych strumieni, ulegnie awarii. Tak długo, jak Twój program nie powoduje lib aby ich użyć, nigdy się nie dowiesz. Na przykład png_default_error zapisuje do stderr, gdy CRC nie pasuje do metadanych PNG. (Normalnie nie jest to problem godny awarii)

Wniosek: nie można mieszać bibliotek VS2012 (Platform Toolset v110/v110_xp) i VS2015+, jeśli używają stdin, stdout i/lub stderr.

Rozwiązanie: przekompiluj swoje biblioteki, które mają __iob_func nierozwiązane symbole z bieżącą wersją VS i pasującym zestawem narzędzi platformy.

 5
Author: Luc Bloom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-02 11:44:35

Użyj wstępnie skompilowanej głowicy SDL2.lib i SDL.lib dla biblioteki twojego projektu VS2015 : https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/sdl-visualstudio-2225.zip

 1
Author: SolutionIsComing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-20 03:43:53

Udało mi się rozwiązać problem.

Źródłem błędu była ta linia kodu, którą można znaleźć w kodzie źródłowym SDLmain.

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

Więc to, co zrobiłem, to edytować kod źródłowy w SDLmain tej linii też:

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

A potem zbudowałem Łańcuch SDL, skopiowałem i zastąpiłem stary łańcuch SDL.lib w moim katalogu biblioteki SDL2 z nowo zbudowanym i edytowanym.

Potem, gdy uruchomiłem mój program z SDL2 nie pojawiły się żadne komunikaty o błędach i Kod działał płynnie.

I Nie wiem, czy to mnie później ugryzie, ale wszystko idzie świetnie.

 0
Author: RockFrenzy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-23 18:49:48

Może się to zdarzyć, gdy połączysz się z msvcrt.dll zamiast msvcr10.dll (lub podobny), który jest dobrym planem. Ponieważ pozwoli Ci to na redystrybucję biblioteki uruchomieniowej Visual Studio w końcowym pakiecie oprogramowania.

To obejście pomaga mi (w 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

Ten fragment nie jest potrzebny w Visual Studio 6 i jego kompilatorze. Dlatego # ifdef.

 0
Author: user2699548,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-22 00:50:25