nierozwiązany symbol zewnętrzny __imp__fprintf i __imp____iob_func, SDL2

108

Czy ktoś mógłby wyjaśnić, co to jest

__imp__fprintf

i

__imp____iob_func

nierozwiązane środki zewnętrzne?

Ponieważ otrzymuję 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 linkowaniu. Podłączyłem wszystko poprawnie, ale z jakiegoś powodu nie można się skompilować.

Próbuję użyć SDL2.

Używam programu Visual Studio 2015 jako kompilatora.

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

RockFrenzy
źródło
1
Czy mógłbyś to udowodnić pokazując proszę ustawienia linkera.
πάντα ῥεῖ
@ πάνταῥεῖ, podłączyłem do SDL2.lib i SDL2main.lib w ustawieniach konsolidatora wejściowego i upewniłem się, że katalogi wskazują właściwy katalog.
RockFrenzy

Odpowiedzi:

123

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

W programie Visual Studio 2015 stdin, stderr i stdout są zdefiniowane w następujący sposób:

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

Ale wcześniej były one definiowane jako:

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

Dlatego teraz __iob_func nie jest już zdefiniowane, co prowadzi do błędu łącza podczas korzystania z pliku .lib skompilowanego z poprzednimi wersjami programu Visual Studio.

Aby rozwiązać ten problem, możesz spróbować zdefiniować __iob_func()siebie, który powinien zwrócić tablicę zawierającą {*stdin,*stdout,*stderr}.

Jeśli chodzi o inne błędy linków dotyczące funkcji stdio (w moim przypadku tak było sprintf()), możesz dodać legacy_stdio_definitions.lib do opcji konsolidatora.

Bóg
źródło
1
Dzięki za namierzenie tego. IIRC problem z {* stdin, * stdout, * stderr} może polegać na tym, że różne jednostki kompilacji mogą mieć swoją „własną” kopię stdin, dlatego te funkcje były wywoływane bezpośrednio.
Steven R. Loomis
3
to rozwiązało również dla mnie, tylko przypomnienie o użyciu extern "C"w deklaracji / definicji.
Vargas
4
Czy ktoś może dokładnie napisać, jak powinna wyglądać funkcja zamiany? Próbowałem różnych wariantów i wciąż otrzymuję błędy kompilacji. Dzięki.
Milan Babuškov
55
extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
PoL0
1
Powyższa definicja iob_func nie działa. Poprawną definicję znajdziesz w odpowiedzi MarkHa. (Nie możesz po prostu zdefiniować funkcji jako tablicy i oczekiwać, że wywołania będą działać.)
Hans Olsson,
59

Dla Milana Babuškova, IMO, dokładnie tak powinna wyglądać funkcja zamiany :-)

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

extern "C" FILE * __cdecl __iob_func(void)
{
    return _iob;
}
smartsl
źródło
5
Po prostu brakuje #ifdef dla MSVC i wersji MSVC <2015
paulm
1
Jak zauważa MarkH w innej odpowiedzi, która wygląda na poprawną, ale nie zadziała.
Hans Olsson
4
@paulm Myślę, że masz na myśli #if defined(_MSC_VER) && (_MSC_VER >= 1900).
Jesse Chisholm
@JesseChisholm może, zależy od tego, czy dotyczy to również każdej znanej przyszłej wersji MSVC, czy nie;)
paulm
42

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

Rodzina funkcji printf i scanf jest teraz zdefiniowana w tekście.

Definicje wszystkich funkcji printf i scanf zostały przeniesione do nagłówków stdio.h , conio.h i innych nagłówków CRT. Jest to przełomowa zmiana, która prowadzi do błędu konsolidatora (LNK2019, nierozwiązany symbol zewnętrzny) dla wszystkich programów, które zadeklarowały te funkcje lokalnie bez uwzględnienia odpowiednich nagłówków CRT. Jeśli to możliwe, należy zaktualizować kod, aby zawierał nagłówki CRT (czyli dodaj #include) i funkcje wbudowane, ale jeśli nie chcesz modyfikować kodu w celu uwzględnienia tych plików nagłówkowych, alternatywnym rozwiązaniem jest dodanie dodatkowego biblioteka do wejścia konsolidatora, legacy_stdio_definitions.lib .

Aby dodać tę bibliotekę do danych wejściowych konsolidatora w środowisku IDE, otwórz menu kontekstowe węzła projektu, wybierz opcję Właściwości, a następnie w oknie dialogowym Właściwości projektu wybierz pozycję Konsolidator i edytuj dane wejściowe konsolidatora, aby dodać starszą wersję_stdio_definitions.lib do średnika oddzielna lista.

Jeśli projekt łączy się z bibliotekami statycznymi, które zostały skompilowane w wersji Visual C ++ wcześniejszej niż 2015, konsolidator może zgłosić nierozwiązany symbol zewnętrzny. Te błędy mogą odnosić się do wewnętrznych definicji stdio dla _iob , _iob_func lub powiązanych importów dla niektórych funkcji stdio w postaci __imp_ *. Firma Microsoft zaleca ponowne skompilowanie wszystkich bibliotek statycznych z najnowszą wersją kompilatora Visual C ++ i bibliotek podczas uaktualniania projektu. Jeśli biblioteka jest biblioteką innej firmy, dla której źródło nie jest dostępne, należy zażądać zaktualizowanego pliku binarnego od strony trzeciej lub hermetyzować użycie tej biblioteki w oddzielnej bibliotece DLL, którą kompilujesz ze starszą wersją kompilatora Visual C ++ i bibliotek.

kingsb
źródło
7
Lub #pragma comment(lib, "legacy_stdio_definitions.lib")- ale to nie rozwiązuje problemu __imp___iob_func- czy jest do tego również starsza biblioteka?
bytecode77
29

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

Wydaje się, że ten symbol nie jest zdefiniowany w żadnej statycznej bibliotece dostarczonej przez Microsoft w ramach 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 używana.

Oto fragment z nagłówków programu Visual Studio 2008:

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

Widzimy więc, że zadaniem funkcji jest zwrócenie początku tablicy obiektów PLIKU (nie uchwytów, „PLIK *” jest uchwytem, ​​PLIK jest podstawową nieprzezroczystą strukturą danych przechowującą ważne elementy stanu). Użytkownikami tej funkcji są trzy makra stdin, stdout i stderr, które są używane do różnych wywołań w stylu 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))

Tak więc podejście zmieniło się, aby funkcja zastępująca zwracała teraz uchwyt pliku, a nie adres tablicy obiektów plików, a makra zmieniły się, aby po prostu wywołać funkcję przekazującą numer identyfikacyjny.

Dlaczego więc nie mogą / my zapewnić kompatybilnego interfejsu API? Istnieją dwie kluczowe zasady, których Microsoft nie może naruszać, jeśli chodzi o ich pierwotną implementację za pośrednictwem __iob_func:

  1. Musi istnieć tablica trzech struktur PLIKÓW, które mogą być indeksowane w taki sam sposób jak poprzednio.
  2. Układ strukturalny PLIKU nie może się zmienić.

Jakakolwiek zmiana w jednym z powyższych oznaczałaby istniejący skompilowany kod powiązany z tym, który poszedłby źle, gdyby wywołano ten interfejs API.

Przyjrzyjmy się, jak zdefiniowano / jest zdefiniowany PLIK.

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;

A więc sedno tego: struktura zmieniła kształt. Istniejący skompilowany kod odwołujący się do __iob_func opiera się na fakcie, ż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 powyższych odpowiedziach nie zadziałałyby (gdyby zostały wywołane) z kilku powodów:

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

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

Tablica FILE _iob zostanie skompilowana za pomocą VS2015, a więc zostanie ułożona jako blok struktur zawierających void *. Zakładając wyrównanie 32-bitowe, elementy te byłyby oddalone od siebie o 4 bajty. Więc _iob [0] jest na offset 0, _iob [1] na 4, a _iob [2] na offset 8. Zamiast tego kod wywołujący oczekuje, że PLIK będzie znacznie dłuższy, wyrównany do 32 bajtów w moim systemie, i tak weźmie adres zwróconej tablicy i doda 0 bajtów, aby dostać się do elementu zerowego (ten jest w porządku), ale dla _iob [1] wywnioskuje, że musi dodać 32 bajty, a dla _iob [2] wydedukuje że musi dodać 64 bajty (bo tak to wyglądało w nagłówkach VS2008). I rzeczywiście zdemontowany kod VS2008 to pokazuje.

Drugim problemem związanym z powyższym rozwiązaniem jest kopiowanie zawartości struktury FILE (* stdin), a nie uchwytu FILE *. Tak więc każdy kod VS2008 szukałby innej podstawowej struktury niż VS2015. Może to zadziałać, jeśli struktura zawiera tylko wskaźniki, ale to duże ryzyko. W każdym razie pierwsza kwestia czyni to nieistotnym.

Jedyny hack, jaki udało mi się wymyślić, to taki, w którym __iob_func chodzi po stosie wywołań, aby dowiedzieć się, którego rzeczywistego uchwytu pliku szuka (na podstawie przesunięcia dodanego do zwróconego adresu) i zwraca obliczoną wartość taką, że daje właściwą odpowiedź. To jest tak samo szalone, jak się wydaje, ale prototyp tylko dla x86 (nie x64) jest wymieniony poniżej dla twojej rozrywki. W moich eksperymentach zadziałało dobrze, ale przebieg może się różnić - niezalecany 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;
}
MarkH
źródło
Prawidłowa odpowiedź to ta, najłatwiejsza poprawka to aktualizacja projektu do VS2015, a następnie kompilacja.
Akumaburn
2
W moim przypadku muszę uaktualnić wiele projektów (projekty C ++ i C #) z programu Visual Studio 2013, aby używać programu Visual Studio 2015 Update 3. Chcę zachować VC100 (kompilator C ++ programu Visual studio 2010) podczas tworzenia projektów w języku C ++, ale mam te same błędy jak powyżej. Naprawiłem imp _fprintf , dodając legacy_stdio_definitions.lib do konsolidatora. Jak mogę naprawić również _imp____iob_func ?
Mohamed BOUZIDI
Zanim odpowiem na moje poprzednie pytanie, czy to normalne, że te błędy występują podczas używania MSBuild 14 i IntelCompiler 2016 oraz VC100 do kompilowania projektów C ++?
Mohamed BOUZIDI
1
co mogę zrobić dla kompilacji x64?
Athos
28

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

  1. Przejdź do http://libsdl.org/download-2.0.php i pobierz kod źródłowy SDL 2.
  2. Otwórz SDL_VS2013.sln w VS2015 . Zostaniesz poproszony o konwersję projektów. Zrób to.
  3. Skompiluj projekt SDL2.
  4. Skompiluj projekt SDL2main.
  5. Użyj nowo wygenerowanych plików wyjściowych SDL2main.lib, SDL2.lib i SDL2.dll w projekcie SDL 2 w VS2015.

źródło
4
BTW, budowanie SDL 2.0.3 wymaga zainstalowania pakietu DirectX SDK z czerwca 2010 roku.
Joe
1
Pracował dla mnie, dzięki !! Ale musiałem tylko skompilować SDL2maini skopiowaćSDL2main.lib
kgwong
10

Nie wiem dlaczego, ale:

#ifdef main
#undef main
#endif

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

XGood
źródło
1
.... Okej ... więc przed wypróbowaniem tego powiedziałem sobie głośno, że jakoś wątpię, żeby to zadziałało, ale to całkowicie się udało ..... czy możesz wyjaśnić, dlaczego to działa ...?
Trevor Hart
1
@TrevorHart Uważam , że nie definiuje "wadliwego" SDL main zawiera odniesienia do "undefined" buforów i jeśli twój używa twoich buforów, to wszystko działa dobrze i dobrze.
XGood
2
To okropne hacki ze złymi ćwiczeniami, ale to 3 wiersze i działa, a dzięki temu nie muszę się męczyć przed budowaniem SDL, więc ... ładnie zrobione.
Cheezmeister
1
@Cheezmeister Złe praktyki i hacki są często wymagane do wszystkiego. Zwłaszcza rzeczy, które nie powinny ich potrzebować.
XGood
7

Łączenie oznacza nieprawidłowe działanie. Zagłębiając się w stdio.h VS2012 i VS2015, zadziałało dla mnie następujące. 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);
}
Volker
źródło
7

Moja rada jest taka, aby nie (próbować) wdrażać __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

Wypróbowałem rozwiązania innych odpowiedzi, ale w końcu zwrócenie FILE*tablicy C nie pasuje do tablicy wewnętrznych struktur IOB systemu Windows. @Volker ma rację, że to nigdy nie będziesz pracować dłużej niż jednej stdin, stdoutlub stderr.

Jeśli biblioteka faktycznie WYKORZYSTUJE jeden z tych strumieni, ulegnie awarii . Dopóki Twój program nie spowoduje, że biblioteka ich użyje, nigdy się nie dowiesz . Na przykład png_default_errorzapisuje, stderrgdy CRC nie pasuje w metadanych PNG. (Zwykle nie jest to problem warty awarii)

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

Rozwiązanie: Ponownie skompiluj biblioteki, które mają __iob_funcnierozwiązane symbole, z bieżącą wersją VS i pasującym zestawem narzędzi platformy.

Luc Bloom
źródło
2

Rozwiązuję ten problem za pomocą następującej funkcji. Używam Visual Studio 2019.

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

ponieważ stdin Wywołanie funkcji zdefiniowanej przez makro, wyrażenie "* stdin" nie jest używane globalny inicjator tablicy. Ale możliwa jest inicjalizacja tablicy lokalnej. przepraszam, jestem słaby z angielskiego.

soen.kr
źródło
1

Dla każdego, kto wciąż szuka odpowiedzi, gdzie powyższe sztuczki nie zadziałały. Łączenie statyczne jest sposobem na rozwiązanie tego problemu. Zmień ustawienia biblioteki Runtime, jak poniżej

Project properties --> C/C++ --> Code generation --> Runtime Library --> Multi-threaded Debug (/MTd) instead of /MDd

Sisir
źródło
Oto dyskusja na temat tego rozwiązania: social.msdn.microsoft.com/Forums/vstudio/en-US/…
Sisir
0

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

Źródłem błędu był ten wiersz kodu, który można znaleźć w kodzie źródłowym SDLmain.

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

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

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

Następnie zbudowałem SDLmain i skopiowałem i zastąpiłem stary SDLmain.lib w katalogu mojej biblioteki SDL2 nowo zbudowanym i edytowanym.

Następnie, gdy uruchomiłem program z SDL2, nie pojawiły się żadne komunikaty o błędach, a kod działał płynnie.

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

RockFrenzy
źródło
Twoja zmiana jest błędem sama w sobie i nie rozwiązałaby problemu opisanego w pytaniu. To tylko zbieg okoliczności, że nie otrzymujesz już błędów konsolidatora, co prawdopodobnie wynika wyłącznie z tego, jak odbudowałeś bibliotekę.
Ross Ridge
@ RossRidge, o tak, to mogło być po prostu to. Ach tak.
RockFrenzy
0

Może się to zdarzyć, gdy łączysz się z msvcrt.dll zamiast msvcr10.dll (lub podobnym), co jest dobrym planem. Ponieważ pozwoli Ci to na redystrybucję biblioteki środowiska uruchomieniowego programu Visual Studio w końcowym pakiecie oprogramowania.

To obejście pomaga mi (w programie 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 przypadku programu Visual Studio 6 i jego kompilatora. Dlatego #ifdef.

user2699548
źródło
0

Aby wprowadzić więcej zamieszania w tym już bogatym wątku, zdarzyło mi się wpaść na ten sam nierozwiązany zewnętrzny na fprintf

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

Nawet jeśli w moim przypadku było to w zupełnie innym kontekście: pod Visual Studio 2005 (Visual Studio 8.0) i błąd występował w moim własnym kodzie (tym samym, który kompilowałem), a nie strony trzeciej.

Zdarzyło się, że ten błąd został wywołany przez opcję / MD w moich flagach kompilatora. Przełączenie na / MT usunęło problem. To dziwne, ponieważ zazwyczaj łączenie statyczne (MT) stwarza więcej problemów niż dynamiczne (MD) ... ale na wypadek, gdyby służyło innym, umieszczam to tam.

Cyrkon
źródło
0

W moim przypadku ten błąd pochodzi z mojej próby usunięcia zależności od biblioteki DLL zależnej od wersji MSVC (msvcr10.dll lub podobnej) i / lub usunięcia statycznej biblioteki wykonawczej, aby usunąć nadmiar tłuszczu z moich plików wykonywalnych.

Używam więc przełącznika linkera / NODEFAULTLIB, mojego samodzielnie utworzonego „msvcrt-light.lib” (google w razie potrzeby) i mainCRTStartup()/ WinMainCRTStartup()wpisów.

Jest to IMHO od czasu Visual Studio 2015, więc trzymałem się starszych kompilatorów.

Jednak definiowanie symbolu _NO_CRT_STDIO_INLINE eliminuje wszelkie kłopoty, a prosta aplikacja „Hello World” ma znowu 3 KB i nie jest zależna od nietypowych bibliotek DLL. Przetestowano w programie Visual Studio 2017.

Henrik Haftmann
źródło
-2

Wklej ten kod do dowolnego ze swoich plików źródłowych i ponownie skompiluj. Pracował dla mnie!

#include stdio.h

PLIK _iob [3];

PLIK * __cdecl __iob_func (void) {

_iob [0] = * stdin;

_iob [0] = * standardowe wyjście;

_iob [0] = * stderr;

return _iob;

}

Deep Patel
źródło
należy dodać formatowanie z `` oraz kilka wyjaśnień
Antonin GAVREL
Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia.
Brian