simbol eksternal yang belum terselesaikan __imp__fprintf dan __imp____iob_func, SDL2

108

Bisakah seseorang menjelaskan apa itu

__imp__fprintf

dan

__imp____iob_func

cara eksternal yang belum terselesaikan?

Karena saya mendapatkan kesalahan ini saat mencoba mengompilasi:

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

Saya sudah dapat mengatakan bahwa masalahnya bukan karena salah menghubungkan. Saya telah menghubungkan semuanya dengan benar, tetapi untuk beberapa alasan itu tidak dapat dikompilasi.

Saya mencoba menggunakan SDL2.

Saya menggunakan Visual Studio 2015 sebagai kompiler.

Saya telah menautkan ke SDL2.lib dan SDL2main.lib di Linker -> Input -> Dependensi Tambahan dan saya telah memastikan bahwa Direktori VC ++ sudah benar.

RockFrenzy
sumber
1
Bisakah Anda membuktikannya dengan menunjukkan pengaturan linker Anda.
πάντα ῥεῖ
@ πάνταῥεῖ, saya telah menautkan ke SDL2.lib dan SDL2main.lib dalam pengaturan input linker dan saya telah memastikan bahwa direktori mengarah ke direktori yang benar.
RockFrenzy

Jawaban:

123

Saya akhirnya tahu mengapa ini terjadi!

Di studio visual 2015, stdin, stderr, stdout didefinisikan sebagai berikut:

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

Tapi sebelumnya, mereka didefinisikan sebagai:

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

Jadi sekarang __iob_func tidak didefinisikan lagi yang menyebabkan kesalahan tautan saat menggunakan file .lib yang dikompilasi dengan versi studio visual sebelumnya.

Untuk mengatasi masalah ini, Anda dapat mencoba mendefinisikan __iob_func()diri Anda sendiri yang harus mengembalikan array yang berisi {*stdin,*stdout,*stderr}.

Mengenai kesalahan tautan lain tentang fungsi stdio (dalam kasus saya itu sprintf()), Anda dapat menambahkan legacy_stdio_definitions.lib ke opsi tautan Anda.

Tuhan
sumber
1
Terima kasih telah melacaknya. IIRC masalah dengan {* stdin, * stdout, * stderr} mungkin unit kompilasi yang berbeda mungkin memiliki salinan stdin 'sendiri', itulah sebabnya fungsi ini dipanggil secara langsung.
Steven R. Loomis
3
yang memecahkan bagi saya juga, hanya pengingat untuk digunakan extern "C"dalam deklarasi / definisi.
Vargas
4
Dapatkah seseorang menulis dengan tepat seperti apa fungsi pengganti itu? Saya mencoba varian yang berbeda dan saya terus mendapatkan kesalahan kompilasi. Terima kasih.
Milan Babuškov
55
extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
PoL0
1
Definisi iob_func di atas tidak berfungsi, lihat jawaban MarkH untuk definisi yang benar. (Anda tidak bisa hanya mendefinisikan fungsi sebagai array dan mengharapkan panggilan berfungsi.)
Hans Olsson
59

Bagi Milan Babuškov, IMO, seperti inilah tampilan fungsi pengganti :-)

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

extern "C" FILE * __cdecl __iob_func(void)
{
    return _iob;
}
smartsl
sumber
5
Baru saja kehilangan #ifdef untuk MSVC dan untuk versi MSVC <2015
paulm
1
Seperti yang dicatat MarkH dalam jawaban lain yang terlihat benar, tetapi tidak akan berhasil.
Hans Olsson
4
@paul saya pikir maksud Anda #if defined(_MSC_VER) && (_MSC_VER >= 1900).
Jesse Chisholm
@JesseChisholm mungkin, tergantung apakah ini juga berlaku untuk setiap versi MSVC masa depan yang diketahui atau tidak;)
paulm
42

Microsoft memiliki catatan khusus tentang ini ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):

Kelompok fungsi printf dan scanf sekarang ditetapkan sebaris.

Definisi dari semua fungsi printf dan scanf telah dipindahkan sebaris ke stdio.h , conio.h , dan header CRT lainnya. Ini adalah perubahan yang dapat menyebabkan error linker (LNK2019, simbol eksternal yang belum terselesaikan) untuk program apa pun yang menyatakan fungsi ini secara lokal tanpa menyertakan header CRT yang sesuai. Jika memungkinkan, Anda harus memperbarui kode untuk menyertakan header CRT (yaitu, menambahkan #include) dan fungsi sebaris, tetapi jika Anda tidak ingin mengubah kode Anda untuk menyertakan file header ini, solusi alternatifnya adalah dengan menambahkan tambahan perpustakaan ke input penaut Anda, legacy_stdio_definitions.lib .

Untuk menambahkan pustaka ini ke input linker Anda di IDE, buka menu konteks untuk node proyek, pilih Properties, lalu di kotak dialog Project Properties, pilih Linker, dan edit Linker Input untuk menambahkan legacy_stdio_definitions.lib ke titik koma daftar -dipisahkan.

Jika proyek Anda menautkan dengan pustaka statis yang dikompilasi dengan rilis Visual C ++ lebih awal dari 2015, penaut mungkin melaporkan simbol eksternal yang belum terselesaikan. Kesalahan ini mungkin merujuk pada definisi stdio internal untuk _iob , _iob_func , atau impor terkait untuk fungsi stdio tertentu dalam bentuk __imp_ *. Microsoft menganjurkan agar Anda mengkompilasi ulang semua pustaka statis dengan versi terbaru dari kompiler dan pustaka Visual C ++ saat Anda memutakhirkan proyek. Jika pustaka adalah pustaka pihak ketiga yang sumbernya tidak tersedia, Anda harus meminta biner yang diperbarui dari pihak ketiga atau merangkum penggunaan pustaka itu ke dalam DLL terpisah yang Anda kompilasi dengan versi lama dari kompiler Visual C ++ dan perpustakaan.

kingsb
sumber
7
Atau #pragma comment(lib, "legacy_stdio_definitions.lib")- tapi ini tidak memperbaiki __imp___iob_func- apakah ada lib warisan untuk ini juga?
bytecode77
29

Seperti yang dijawab di atas, jawaban yang benar adalah mengkompilasi semuanya dengan VS2015, tetapi untuk kepentingan berikut ini adalah analisis saya tentang masalah tersebut.

Simbol ini tampaknya tidak didefinisikan di pustaka statis mana pun yang disediakan oleh Microsoft sebagai bagian dari VS2015, yang agak aneh karena yang lainnya. Untuk mengetahui alasannya, kita perlu melihat deklarasi fungsi itu dan, yang lebih penting, bagaimana penggunaannya.

Berikut potongan dari header Visual Studio 2008:

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

Jadi kita dapat melihat bahwa tugas fungsinya adalah mengembalikan awal larik objek FILE (bukan menangani, "FILE *" adalah pegangannya, FILE adalah struktur data buram yang mendasari yang menyimpan barang negara penting). Pengguna fungsi ini adalah tiga makro stdin, stdout dan stderr yang digunakan untuk berbagai panggilan fscanf, gaya fprintf.

Sekarang mari kita lihat bagaimana Visual Studio 2015 mendefinisikan hal yang sama:

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

Jadi pendekatannya telah berubah untuk fungsi pengganti sekarang mengembalikan pegangan file daripada alamat dari array objek file, dan makro telah berubah untuk hanya memanggil fungsi yang meneruskan nomor pengenal.

Jadi mengapa mereka tidak / kami menyediakan API yang kompatibel? Ada dua aturan utama yang tidak dapat dilanggar Microsoft dalam hal implementasi aslinya melalui __iob_func:

  1. Harus ada larik dari tiga struktur FILE yang dapat diindeks dengan cara yang sama seperti sebelumnya.
  2. Tata letak struktural FILE tidak dapat diubah.

Setiap perubahan di salah satu hal di atas berarti kode terkompilasi yang ada yang ditautkan ke sana akan menjadi sangat salah jika API itu dipanggil.

Mari kita lihat bagaimana FILE dulu / didefinisikan.

Pertama definisi VS2008 FILE:

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

Dan sekarang definisi FILE VS2015:

typedef struct _iobuf
{
    void* _Placeholder;
} FILE;

Jadi, inilah intinya: struktur telah berubah bentuk. Kode terkompilasi yang ada yang merujuk ke __iob_func bergantung pada fakta bahwa data yang dikembalikan adalah array yang dapat diindeks dan dalam array itu elemen-elemennya memiliki jarak yang sama.

Solusi yang mungkin disebutkan dalam jawaban di atas di sepanjang baris ini tidak akan berfungsi (jika dipanggil) karena beberapa alasan:

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

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

Larik FILE _iob akan dikompilasi dengan VS2015 dan karenanya akan diletakkan sebagai blok struktur yang berisi void *. Dengan asumsi perataan 32-bit, elemen-elemen ini akan terpisah 4 byte. Jadi _iob [0] berada di offset 0, _iob [1] di offset 4 dan _iob [2] di offset 8. Kode pemanggil malah akan mengharapkan FILE lebih panjang, sejajar pada 32 byte di sistem saya, dan seterusnya itu akan mengambil alamat dari array yang dikembalikan dan menambahkan 0 byte untuk sampai ke elemen nol (yang itu tidak apa-apa), tetapi untuk _iob [1] itu akan menyimpulkan bahwa ia perlu menambahkan 32 byte dan untuk _iob [2] itu akan menyimpulkan bahwa ia perlu menambahkan 64-byte (karena itulah tampilannya di header VS2008). Dan memang kode yang dibongkar untuk VS2008 menunjukkan hal ini.

Masalah sekunder dengan solusi di atas adalah bahwa ia menyalin konten dari struktur FILE (* stdin), bukan pegangan FILE *. Jadi setiap kode VS2008 akan melihat struktur dasar yang berbeda dengan VS2015. Ini mungkin berhasil jika struktur hanya berisi petunjuk, tetapi itu risikonya besar. Bagaimanapun, masalah pertama membuat ini tidak relevan.

Satu-satunya peretasan yang bisa saya impikan adalah di mana __iob_func menjalankan tumpukan panggilan untuk mengetahui pegangan file aktual mana yang mereka cari (berdasarkan offset yang ditambahkan ke alamat yang dikembalikan) dan mengembalikan nilai yang dihitung sedemikian rupa sehingga itu memberikan jawaban yang benar. Ini sama gilanya kedengarannya, tetapi prototipe untuk x86 saja (bukan x64) tercantum di bawah ini untuk hiburan Anda. Ini berfungsi dengan baik dalam eksperimen saya, tetapi jarak tempuh Anda mungkin berbeda - tidak disarankan untuk penggunaan produksi!

#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
sumber
Jawaban yang benar adalah yang ini, perbaikan termudah adalah seperti yang dinyatakan untuk memutakhirkan proyek ke VS2015 dan kemudian mengkompilasi.
Akumaburn
2
Dalam kasus saya, saya perlu memutakhirkan banyak proyek (proyek C ++ dan C #) dari visual studio 2013 untuk menggunakan Visual Studio 2015 Update 3. Saya ingin menyimpan VC100 (Visual studio 2010 C ++ compiler) saat membangun proyek C ++ tetapi saya memiliki kesalahan yang sama seperti di atas. Saya memperbaiki imp _fprintf dengan menambahkan legacy_stdio_definitions.lib ke linker. Bagaimana cara memperbaiki juga _imp____iob_func ?
Mohamed BOUZIDI
Sebelum menjawab pertanyaan saya sebelumnya, Apakah normal jika kesalahan ini terjadi saat menggunakan msbuild 14 dan IntelCompiler 2016 dan VC100 untuk mengkompilasi proyek C ++?
Mohamed BOUZIDI
1
apa yang dapat saya lakukan untuk kompilasi x64?
athos
28

Saya memiliki masalah yang sama di VS2015. Saya telah menyelesaikannya dengan menyusun sumber SDL2 di VS2015.

  1. Buka http://libsdl.org/download-2.0.php dan unduh kode sumber SDL 2.
  2. Buka SDL_VS2013.sln di VS2015 . Anda akan diminta untuk mengubah proyek. Lakukan.
  3. Kompilasi proyek SDL2.
  4. Kompilasi proyek utama SDL2.
  5. Gunakan file keluaran baru yang dihasilkan SDL2main.lib, SDL2.lib dan SDL2.dll dalam proyek SDL 2 Anda di VS2015.

sumber
4
BTW, membangun SDL 2.0.3 membutuhkan DirectX SDK Juni 2010 untuk diinstal.
Joe
1
Bekerja untuk saya, terima kasih !! Tapi saya hanya perlu mengkompilasi SDL2maindan menyalinSDL2main.lib
kgwong
10

Saya tidak tahu kenapa tapi:

#ifdef main
#undef main
#endif

Setelah termasuk tetapi sebelum utama Anda harus memperbaikinya dari pengalaman saya.

XGood
sumber
1
.... Oke .... jadi sebelum mencoba ini saya dengan suara berkata pada diri saya sendiri bahwa saya ragu ini akan berhasil namun itu benar-benar berhasil ..... dapatkah Anda menjelaskan mengapa ini berhasil ...?
Trevor Hart
1
@TrevorHart Saya percaya bahwa ini tidak mendefinisikan referensi utama SDL yang "salah" termasuk ke buffer "tidak ditentukan" dan jika milik Anda menggunakan buffer Anda, maka semuanya berfungsi dengan baik dan baik.
The XGood
2
Ini adalah praktik peretasan yang buruk tetapi ini 3 baris dan berhasil dan itu menyelamatkan saya dari keharusan untuk melakukan rabbithole ke dalam membangun SDL jadi ... bagus sekali.
Cheezmeister
1
@ Cheezmeister Praktik buruk dan peretasan sering kali diperlukan untuk segala hal. Terutama hal-hal yang seharusnya tidak mereka butuhkan.
The XGood
7

Untuk menghubungkan berarti tidak berfungsi dengan baik. Menggali stdio.h dari VS2012 dan VS2015, hal berikut berhasil untuk saya. Sayangnya, Anda harus memutuskan apakah ini akan bekerja untuk salah satu {stdin, stdout, stderr}, tidak lebih dari satu.

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
sumber
7

Saran saya adalah jangan (mencoba) mengimplementasikan __iob_func.

Saat memperbaiki kesalahan ini:

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

Saya mencoba solusi jawaban lain, tetapi pada akhirnya, mengembalikan FILE*C-array tidak sesuai dengan array struktur IOB internal Windows. @Volker benar bahwa itu tidak akan pernah berhasil untuk lebih dari satu stdin, stdoutatau stderr.

Jika perpustakaan benar-benar MENGGUNAKAN salah satu aliran tersebut, itu akan macet . Selama program Anda tidak menyebabkan lib untuk menggunakannya, Anda tidak akan pernah tahu . Misalnya, png_default_errormenulis ke stderrsaat CRC tidak cocok di metadata PNG. (Biasanya bukan masalah crash-worth)

Kesimpulan: Tidak mungkin untuk mencampur VS2012 (Platform Toolset v110 / v110_xp) dan perpustakaan VS2015 +, jika mereka menggunakan stdin, stdout dan / atau stderr.

Solusi: Kompilasi ulang pustaka Anda yang memiliki __iob_funcsimbol yang belum terselesaikan dengan versi VS Anda saat ini dan Platform Toolset yang cocok.

Luc Bloom
sumber
2

Saya menyelesaikan masalah ini dengan fungsi berikut. Saya menggunakan Visual Studio 2019.

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

karena stdin pemanggilan fungsi yang ditentukan makro, ekspresi "* stdin" tidak dapat digunakan penginisialisasi larik global. Tetapi penginisialisasi array lokal dimungkinkan. maaf, saya miskin bahasa inggris.

soen.kr
sumber
1

Untuk siapa saja yang masih mencari jawaban di mana trik di atas tidak berhasil. Penautan statis adalah cara untuk mengatasi masalah ini. Ubah pengaturan perpustakaan Runtime Anda seperti di bawah ini

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

Sisir
sumber
Berikut adalah diskusi tentang solusi ini: social.msdn.microsoft.com/Forums/vstudio/en-US/…
Sisir
0

Saya berhasil memperbaiki masalah.

Sumber kesalahan adalah baris kode ini, yang dapat ditemukan di kode sumber utama SDL.

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

Jadi yang saya lakukan adalah mengedit kode sumber di SDLmain baris itu juga:

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

Dan kemudian saya membangun SDLmain dan menyalin dan mengganti SDLmain.lib lama di direktori perpustakaan SDL2 saya dengan yang baru dibangun dan diedit.

Kemudian ketika saya menjalankan program saya dengan SDL2 tidak ada pesan kesalahan yang muncul dan kode berjalan dengan lancar.

Saya tidak tahu apakah ini akan menggigit saya nanti, tetapi karena semuanya berjalan baik.

RockFrenzy
sumber
Perubahan Anda adalah kesalahan dengan sendirinya dan tidak akan memperbaiki masalah yang dijelaskan dalam pertanyaan Anda. Ini hanya kebetulan bahwa Anda tidak lagi mendapatkan kesalahan penaut, yang mungkin semata-mata merupakan hasil dari cara Anda membuat ulang pustaka.
Ross Ridge
@RossRidge, oh ya itu mungkin saja. Ah baiklah.
RockFrenzy
0

Hal ini dapat terjadi jika Anda menautkan ke msvcrt.dll, bukan msvcr10.dll (atau serupa), yang merupakan rencana yang bagus. Karena itu akan membebaskan Anda untuk mendistribusikan kembali perpustakaan runtime Visual Studio Anda di dalam paket perangkat lunak akhir Anda.

Solusi tersebut membantu saya (di 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

Potongan ini tidak diperlukan untuk Visual Studio 6 dan kompilernya. Oleh karena itu, #ifdef.

pengguna2699548
sumber
0

Untuk membawa lebih banyak kebingungan di utas yang sudah kaya ini, saya kebetulan menemukan eksternal yang belum terselesaikan yang sama di fprintf

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

Bahkan jika dalam kasus saya itu dalam konteks yang agak berbeda: di bawah Visual Studio 2005 (Visual Studio 8.0) dan kesalahan terjadi di kode saya sendiri (yang sama yang saya kompilasi), bukan pihak ketiga.

Kebetulan kesalahan ini dipicu oleh opsi / MD di flag compiler saya. Beralih ke / MT menghilangkan masalah. Ini aneh karena biasanya, menghubungkan secara statis (MT) menimbulkan lebih banyak masalah daripada secara dinamis (MD) ... tetapi kalau-kalau itu melayani yang lain, saya taruh di sana.

Zirkonium
sumber
0

Dalam kasus saya, kesalahan ini berasal dari percobaan saya untuk menghapus ketergantungan ke DLL perpustakaan runtime tergantung versi MSVC (msvcr10.dll atau lebih) dan / atau menghapus perpustakaan runtime statis juga, untuk menghilangkan kelebihan lemak dari file executable saya.

Jadi saya menggunakan / NODEFAULTLIB linker switch, "msvcrt-light.lib" buatan saya (google untuk itu bila Anda membutuhkannya), dan mainCRTStartup()/ WinMainCRTStartup()entries.

Ini adalah IMHO sejak Visual Studio 2015, jadi saya tetap menggunakan kompiler lama.

Namun, mendefinisikan simbol _NO_CRT_STDIO_INLINE menghilangkan semua kerumitan, dan aplikasi "Hello World" sederhana lagi-lagi berukuran 3 KB dan tidak bergantung pada DLL yang tidak biasa. Diuji dalam Visual Studio 2017.

Henrik Haftmann
sumber
-2

Tempel kode ini di salah satu file sumber Anda dan buat ulang. Bekerja untuk saya!

#include stdio.h

FILE _iob [3];

FILE * __cdecl __iob_func (tidak berlaku) {

_iob [0] = * stdin;

_iob [0] = * stdout;

_iob [0] = * stderr;

kembali _iob;

}

Deep Patel
sumber
Anda harus menambahkan pemformatan dengan "dan juga beberapa penjelasan
Antonin GAVREL
Meskipun kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan tentang bagaimana dan mengapa ini menyelesaikan masalah akan sangat membantu meningkatkan kualitas posting Anda, dan mungkin menghasilkan lebih banyak suara. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, bukan hanya orang yang bertanya sekarang. Harap edit jawaban Anda untuk menambahkan penjelasan dan memberikan indikasi batasan dan asumsi apa yang berlaku.
Brian