`` WinMain @ 16 '' için tanımsız başvuru


110

Kullanarak bir program oluşturmaya çalıştığımda Eclipse CDT, aşağıdakileri alıyorum:

/mingw/lib/libmingw32.a(main.o):main.c:(.text+0x106): `WinMain @ 16 için tanımsız başvuru

Neden? Ve bu sorunu nasıl çözebilirim?

Yanıtlar:


184

Aşağıdaki Windows API düzeyindeki programı düşünün:

#define NOMINMAX
#include <windows.h>

int main()
{
    MessageBox( 0, "Blah blah...", "My Windows app!", MB_SETFOREGROUND );
}

Şimdi onu GNU araç zincirini (yani g ++) kullanarak oluşturalım, özel seçenekler yok. Burayagnuc bunun için kullandığım bir toplu iş dosyası. Yalnızca g ++ 'yı daha standart hale getirmek için seçenekler sağlar:

C: \ test> gnuc x.cpp

C: \ test> objdump -x a.exe | findstr / i "^ altsistem"
Alt sistem 00000003 (Windows CUI)

C: \ test> _

Bu, bağlayıcının varsayılan olarak çalıştırılabilir bir konsol alt sistemi ürettiği anlamına gelir . Alt sistem dosyası başlığında değer programı gerektirir hangi hizmetlerin Windows bildirir. Bu durumda, konsol sistemiyle, programın bir konsol penceresi gerektirmesi.

Bu aynı zamanda komut yorumlayıcısının programın tamamlanmasını beklemesine neden olur.

Şimdi bunu GUI alt sistemi ile oluşturalım , bu sadece programın bir konsol penceresi gerektirmediği anlamına gelir:

C: \ test> gnuc x.cpp -mwindows

C: \ test> objdump -x a.exe | findstr / i "^ altsistem"
Alt sistem 00000002 (Windows GUI)

C: \ test> _

-mwindowsBayrak sadece yarı belgelenmiş olmasına rağmen umarım şimdiye kadar sorun olmaz .

Bu yarı belgelenmiş bayrak olmadan inşa etmek, bağlayıcıya hangi alt sistem değerini istediğini daha spesifik olarak söylemek zorunda kalacak ve bu durumda bazı Windows API içe aktarma kitaplıklarının genel olarak açıkça belirtilmesi gerekecektir:

C: \ test> gnuc x.cpp -Wl, -subsystem, windows

C: \ test> objdump -x a.exe | findstr / i "^ altsistem"
Alt sistem 00000002 (Windows GUI)

C: \ test> _

Bu, GNU araç zinciri ile iyi çalıştı.

Peki ya Microsoft araç zinciri, yani Visual C ++?

Bir konsol alt sistemi yürütülebilir dosyası olarak oluşturmak iyi çalışıyor:

C: \ test> msvc x.cpp user32.lib
x.cpp

C: \ test> dumpbin / başlıklar x.exe | / i "alt sistem" bul | bul / i "Windows"
               3 alt sistem (Windows CUI)

C: \ test> _

Ancak, Microsoft'un araç zinciri oluştururken GUI alt sistemi olarak varsayılan olarak çalışmaz:

C: \ test> msvc x.cpp user32.lib / link / subsystem: windows
x.cpp
LIBCMT.lib (wincrt0.obj): hata LNK2019: __tmainCRTStartu işlevinde başvurulan çözümlenmemiş harici sembol _WinMain @ 16
p
x.exe: önemli hata LNK1120: 1 çözülmemiş harici

C: \ test> _

Teknik olarak bunun nedeni, Microsoft'un bağlayıcısının GUI alt sistemi için varsayılan olarak standart olmamasıdır . Varsayılan olarak, alt sistem GUI olduğunda, Microsoft'un bağlayıcısı bir çalışma zamanı kitaplığı giriş noktası kullanır ; bu, makine kodu yürütmenin başladığı ve winMainCRTStartupstandart WinMainyerine Microsoft'un standart dışı çağrısı olarak adlandırılan işlevdir main.

Yine de bunu düzeltmek için önemli bir şey yok.

Tek yapmanız gereken, Microsoft'un linker'ına hangi giriş noktasının kullanılacağını, yani mainCRTStartupstandardı çağıran main:

C: \ test> msvc x.cpp user32.lib / link / subsystem: windows / entry: mainCRTStartup
x.cpp

C: \ test> dumpbin / başlıklar x.exe | / i "alt sistem" bul | bul / i "Windows"
               2 alt sistem (Windows GUI)

C: \ test> _

Sorun değil ama çok sıkıcı. Ve o kadar esrarengiz ve gizlidir ki, çoğunlukla yalnızca Microsoft'un standart olmayan varsayılan araçlarını kullanan çoğu Windows programcısı bunu bilmiyor ve yanlışlıkla bir Windows GUI alt sistemi programının standart WinMainyerine standart dışı olması gerektiğini düşünüyor. main. Geçerken, C ++ 0x ile Microsoft bununla ilgili bir sorun yaşayacaktır, çünkü derleyicinin bağımsız mı yoksa barındırılı mı olduğunu duyurması gerekir (barındırıldığında standardı desteklemesi gerekir main).

Neyse, bu g ++ nedeni bu olabilir şikayet WinMainMicrosoft'un araçları GUI alt sistemi programları için varsayılan olarak gerektirdiğini saçma standart olmayan başlatma fonksiyonu var: Eksik.

Ancak yukarıda görebileceğiniz gibi, g ++ 'nın mainbir GUI alt sistem programı için bile standartla bir sorunu yoktur .

Peki sorun ne olabilir?

Eh, muhtemelen vardır eksik bir main. Ve muhtemelen sende de (uygun) WinMainyok! Ve sonra g ++, aradıktan sonra main(böyle değil) ve Microsoft'un standart dışı WinMain(böyle değil), ikincisinin eksik olduğunu bildirir.

Boş bir kaynakla test etme:

C: \ test> nul> y.cpp yazın

C: \ test> gnuc y.cpp -mwindows
c: / program files / mingw / bin /../ lib / gcc / mingw32 / 4.4.1 /../../../ libmingw32.a (main.o): main.c :(. metin + 0xd2 ): tanımsız referen
ce `` WinMain @ 16 ''
Collect2: ld 1 çıkış durumu döndürdü

C: \ test> _

3
@Alf P. Steinbach. Güzel cevabınız için çok teşekkürler. Gelince All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. Eclipse CDTKomut satırını kullanmadığım için bunu yapmanın bir yolu var mı ? Teşekkürler
Sadelik

1
@ user588855: g ++ kullandığınız için bu (muhtemelen) sizin için geçerli değildir. Yalnızca sondaki kısım (muhtemelen) geçerlidir. Yani, a mainveya a tanımlayın veya WinMainilgili dosyanın projeye dahil edildiğinden emin olun. Şerefe,
Şerefe ve hth. - Alf

@Alf P. Steinbach. Eğer tanımlayarak ne anlama geliyor mainya winmain? Teşekkürler
Sadelik

1
Şu kodu içeren main.cpp adında bir dosya yaptım: int main () {}
Gerçekten

3
Olumsuz oy kullananlardan her biri olumsuz oyu açıklasa iyi olur. Muhtemelen diğer okuyucularda aynı yanlış anlama var (her ne ise) ve sonra bunu açıklayabiliriz. Bazıları yanıltılmak yerine herkes bundan faydalanacaktır. Lütfen olumsuz oyunuzu açıklayın. Teşekkür ederim.
Şerefe ve hth. - Alf

68

Yukarıdaki gönderiyi Cheers ve hth tarafından özetlemek gerekirse. - Alf, sahip olduğunuzdan main()veya WinMain()tanımladığınızdan emin olun ve g ++ doğru olanı yapmalıdır.

Benim sorunum, main()kazara bir ad alanı içinde tanımlanmış olmasıydı.


Tüm bunlarla ilgili önemli bir şeyin farkına vardım. Benim durumumda, herhangi bir argüman (argc, argv) bildirmediğim için main () bulamıyordu. Bir kez eklendiğinde, ana bulundu. Ayrıca, bunun nasıl çalıştığının doğası, mingw'nin WinMain'i çağıran kendi ana ağını sağlayarak yardım etmeye çalıştığı anlamına gelir. GUI programlarında yalnızca WinMain bulunur ve mingw'deki ana saplama oraya ulaşmak için kullanılır. Bir ana bağlantınız varsa, onun yerine onu kullanır.
Jeff Muir

extern "C" int main (void) benim için sorunu çözdü
dryler

33

Uygulamamı SDL ile derlerken bu hatayla karşılaşıyordum. Bunun nedeni, SDL'nin SDL_main.h'de kendi ana işlevini tanımlamasıydı. SDL'yi önlemek için ana işlevi tanımlayın, SDL.h başlığı dahil edilmeden önce bir SDL_MAIN_HANDLED makrosu tanımlanmalıdır.


Mükemmel cevap! +1
Mohammad Kanan

Çok teşekkürler! Bu komut çalışır: gcc main.c -I "E: \ Libs \ SDL2-devel-2.0.12-mingw \ SDL2-2.0.12 \ i686-w64-mingw32 \ include" -I "E: \ Libs \ SDL2_ttf- devel-2.0.15-mingw \ SDL2_ttf-2.0.15 \ i686-w64-mingw32 \ include "-L" E: \ Libs \ SDL2-devel-2.0.12-mingw \ SDL2-2.0.12 \ i686-w64- mingw32 \ lib "-L" E: \ Libs \ SDL2_ttf-devel-2.0.15-mingw \ SDL2_ttf-2.0.15 \ i686-w64-mingw32 \ lib "-lSDL2 -lSDL2main -lSDL2_ttf -o app.exe
8Observer8

5

Oluşturmadan önce .c dosyanızı kaydetmeyi deneyin. Bilgisayarınızın, içinde bilgi olmayan bir dosyaya giden yolu referans gösterdiğine inanıyorum.

--C projeleri oluştururken benzer bir sorun yaşandı


Bu aslında sorunumu çözdü ve daha fazla dikkat çekmesine yardımcı olmak için bu yorumu bırakıyorum.
David Chen

0

Tüm Dosyaların Projenize Dahil Edildiğini Kontrol Edin:

CLion'u güncelledikten sonra aynı hatayı aldım. Saatlerce uğraştıktan sonra, dosyalarımdan birinin proje hedefine dahil olmadığını fark ettim. Onu aktif projeye geri ekledikten sonra, winmain16 için tanımsız referansı almayı bıraktım ve kod derlendi.

Düzenleme: IDE'nizdeki yapı ayarlarını kontrol etmek de faydalı olacaktır.

(Bu hatanın yakın zamanda IDE'yi güncellemeyle ilgili olup olmadığından emin değilim - nedensel veya basitçe bağıntılı olabilir. Bu faktör hakkında herhangi bir fikirle yorum yapmaktan çekinmeyin!)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.