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.
c++
sdl-2
visual-studio-2015
unresolved-external
RockFrenzy
sumber
sumber
Jawaban:
Saya akhirnya tahu mengapa ini terjadi!
Di studio visual 2015, stdin, stderr, stdout didefinisikan sebagai berikut:
Tapi sebelumnya, mereka didefinisikan sebagai:
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.sumber
extern "C"
dalam deklarasi / definisi.extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
Bagi Milan Babuškov, IMO, seperti inilah tampilan fungsi pengganti :-)
sumber
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
.Microsoft memiliki catatan khusus tentang ini ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):
sumber
#pragma comment(lib, "legacy_stdio_definitions.lib")
- tapi ini tidak memperbaiki__imp___iob_func
- apakah ada lib warisan untuk ini juga?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:
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:
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:
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:
Dan sekarang definisi FILE VS2015:
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:
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!
sumber
Saya memiliki masalah yang sama di VS2015. Saya telah menyelesaikannya dengan menyusun sumber SDL2 di VS2015.
sumber
SDL2main
dan menyalinSDL2main.lib
Saya tidak tahu kenapa tapi:
Setelah termasuk tetapi sebelum utama Anda harus memperbaikinya dari pengalaman saya.
sumber
Solusi yang lebih baru untuk masalah ini: Gunakan libs sdl terbaru di
" https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/?C=M;O=D "
Mereka tampaknya telah memperbaiki masalah, meskipun itu hanya pustaka 32 bit (menurut saya).
sumber
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.
sumber
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 satustdin
,stdout
ataustderr
.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_error
menulis kestderr
saat 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_func
simbol yang belum terselesaikan dengan versi VS Anda saat ini dan Platform Toolset yang cocok.sumber
Gunakan SDL2main.lib dan SDL.lib yang telah dikompilasi sebelumnya untuk perpustakaan proyek VS2015 Anda: https://buildbot.libsdl.org/sdl-builds/sdl-visualstudio/sdl-visualstudio-2225.zip
sumber
Saya menyelesaikan masalah ini dengan fungsi berikut. Saya menggunakan Visual Studio 2019.
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.
sumber
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
sumber
Saya berhasil memperbaiki masalah.
Sumber kesalahan adalah baris kode ini, yang dapat ditemukan di kode sumber utama SDL.
Jadi yang saya lakukan adalah mengedit kode sumber di SDLmain baris itu juga:
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.
sumber
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):
Potongan ini tidak diperlukan untuk Visual Studio 6 dan kompilernya. Oleh karena itu, #ifdef.
sumber
Untuk membawa lebih banyak kebingungan di utas yang sudah kaya ini, saya kebetulan menemukan eksternal yang belum terselesaikan yang sama di fprintf
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.
sumber
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.
sumber
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;
}
sumber