riferimento indefinito a "WinMain @ 16"


110

Quando provo a creare un programma utilizzando Eclipse CDT, ottengo quanto segue:

/mingw/lib/libmingw32.a(main.o):main.c:(.text+0x106): riferimento non definito a `WinMain @ 16

Perché? E come posso risolvere questo problema?

Risposte:


184

Considera il seguente programma a livello di API di Windows:

#define NOMINMAX
#include <windows.h>

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

Ora costruiamolo usando la toolchain GNU (cioè g ++), senza opzioni speciali. Ecco gnucsolo un file batch che utilizzo per questo. Fornisce solo opzioni per rendere g ++ più standard:

C: \ test> gnuc x.cpp

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

C: \ test> _

Ciò significa che il linker per impostazione predefinita ha prodotto un eseguibile del sottosistema della console . Il valore del sottosistema nell'intestazione del file indica a Windows quali servizi richiede il programma. In questo caso, con il sistema di console, il programma richiede una finestra di console.

Ciò fa sì che l'interprete dei comandi attenda anche il completamento del programma.

Ora costruiamolo con il sottosistema GUI , il che significa semplicemente che il programma non richiede una finestra della console:

C: \ test> gnuc x.cpp -mwindows

C: \ test> objdump -x a.exe | findstr / i "^ sottosistema"
Sottosistema 00000002 (GUI di Windows)

C: \ test> _

Si spera che finora sia OK, anche se la -mwindowsbandiera è solo semi-documentata.

Costruendo senza quel flag semi-documentato si dovrebbe dire in modo più specifico al linker quale valore di sottosistema si desidera, e alcune librerie di importazione dell'API di Windows dovranno quindi in generale essere specificate esplicitamente:

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

C: \ test> objdump -x a.exe | findstr / i "^ sottosistema"
Sottosistema 00000002 (GUI di Windows)

C: \ test> _

Ha funzionato bene, con la toolchain GNU.

Ma per quanto riguarda la toolchain di Microsoft, ovvero Visual C ++?

Bene, la creazione di un eseguibile del sottosistema della console funziona bene:

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

C: \ test> dumpbin / headers x.exe | trova / i "sottosistema" | trova / i "Windows"
               3 sottosistema (Windows CUI)

C: \ test> _

Tuttavia, con la creazione della toolchain di Microsoft come sottosistema GUI non funziona per impostazione predefinita:

C: \ test> msvc x.cpp user32.lib / link / subsystem: windows
x.cpp
LIBCMT.lib (wincrt0.obj): errore LNK2019: simbolo esterno non risolto _WinMain @ 16 referenziato nella funzione ___tmainCRTStartu
p
x.exe: errore irreversibile LNK1120: 1 esterni non risolti

C: \ test> _

Tecnicamente questo è perché il linker di Microsoft non è standard per impostazione predefinita per il sottosistema GUI . Per impostazione predefinita, quando il sottosistema è la GUI, il linker di Microsoft utilizza un punto di ingresso della libreria runtime , la funzione in cui inizia l'esecuzione del codice macchina, chiamata winMainCRTStartup, che chiama Microsoft non standard WinMainanziché standard main.

Non è un grosso problema risolverlo, però.

Tutto quello che devi fare è dire al linker di Microsoft quale punto di ingresso utilizzare, vale a dire mainCRTStartup, che chiama standard main:

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

C: \ test> dumpbin / headers x.exe | trova / i "sottosistema" | trova / i "Windows"
               2 sottosistema (GUI di Windows)

C: \ test> _

Nessun problema, ma molto noioso. E così arcano e nascosto che la maggior parte dei programmatori Windows, che per lo più utilizzano solo strumenti Microsoft non standard per impostazione predefinita, non ne sono nemmeno a conoscenza e pensano erroneamente che un programma del sottosistema della GUI di Windows "debba" avere uno non standard WinMainanziché uno standard main. Per inciso, con C ++ 0x Microsoft avrà un problema con questo, poiché il compilatore deve quindi annunciare se è indipendente o ospitato (quando ospitato deve supportare lo standard main).

Ad ogni modo, questo è il motivo per cui g ++ può lamentarsi della WinMainmancanza: è una sciocca funzione di avvio non standard che gli strumenti di Microsoft richiedono per impostazione predefinita per i programmi del sottosistema della GUI.

Ma come puoi vedere sopra, g ++ non ha problemi con lo standard mainanche per un programma di sottosistema GUI.

Allora quale potrebbe essere il problema?

Beh, probabilmente ti manca un file main. E probabilmente non ne hai neanche uno (corretto) WinMain! E poi g ++, dopo aver cercato main(no tale), e Microsoft non standard WinMain(no tale), segnala che quest'ultimo manca.

Test con una fonte vuota:

C: \ test> digita nul> y.cpp

C: \ test> gnuc y.cpp -mwindows
c: / file di programma / mingw / bin /../ lib / gcc / mingw32 / 4.4.1 /../../../ libmingw32.a (main.o): main.c :(. text + 0xd2 ): referen non definito
ce a "WinMain @ 16"
collect2: ld ha restituito 1 stato di uscita

C: \ test> _

3
@Alf P. Steinbach. Grazie mille per la tua bella risposta. Quanto a All you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. C'è un modo per farlo Eclipse CDTvisto che non sto usando la riga di comando. Grazie
Semplicità

1
@ user588855: dato che stai usando g ++, questo (probabilmente) non ti riguarda. Solo la parte alla fine (probabilmente) si applica. Cioè, definisci a maino a WinMain, o, assicurati che il file rilevante sia incluso nel progetto. Saluti,
Saluti e salute. - Alf

@Alf P. Steinbach. Cosa intendi definendo maino winmain? Grazie
Semplicità

1
Ho appena creato un file chiamato main.cpp che aveva il codice: int main () {}
Effettivamente il

3
Sarei carino se ogni downvoter potesse spiegare il downvote. Forse altri lettori hanno la stessa idea sbagliata (qualunque essa sia), e allora potremmo chiarirlo. Tutti ne trarrebbero vantaggio, invece di essere fuorviati. Quindi, per favore spiega il tuo voto negativo. Grazie.
Saluti e salute. - Alf

68

Per riassumere il post sopra di Cheers e hth. - Alf, assicurati di avere main()o WinMain()definito e g ++ dovrebbe fare la cosa giusta.

Il mio problema era che main()era stato definito accidentalmente all'interno di uno spazio dei nomi.


Ho appena realizzato qualcosa di importante in tutto questo. Nel mio caso, non trovava main () poiché non ho dichiarato alcun argomento (argc, argv). Una volta aggiunto, ha trovato main. Inoltre, la natura di come funziona significa che mingw sta cercando di aiutare fornendo il proprio main che a sua volta chiama WinMain. I programmi GUI avrebbero solo WinMain e lo stub principale in mingw viene utilizzato per arrivarci. Se hai un main, allora usa quello.
Jeff Muir

extern "C" int main (void) ha risolto il problema per me
asciugatrice

33

Ho riscontrato questo errore durante la compilazione della mia applicazione con SDL. Ciò è stato causato da SDL che definisce la propria funzione principale in SDL_main.h. Per impedire a SDL di definire la funzione principale, è necessario definire una macro SDL_MAIN_HANDLED prima di includere l'intestazione SDL.h.


Bella risposta! +1
Mohammad Kanan

Molte grazie! Questo comando funziona: 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

Prova a salvare il tuo file .c prima di crearlo. Credo che il tuo computer stia facendo riferimento a un percorso a un file senza informazioni al suo interno.

- Ha avuto un problema simile durante la creazione di progetti C.


Questo ha effettivamente risolto il mio problema e lascio questo commento per aiutarlo a ottenere più attenzione.
David Chen,

0

Verifica che tutti i file siano inclusi nel tuo progetto:

Ho visualizzato lo stesso errore dopo aver aggiornato cLion. Dopo ore di armeggiare, ho notato che uno dei miei file non era incluso nel target del progetto. Dopo averlo aggiunto di nuovo al progetto attivo, ho smesso di ottenere il riferimento indefinito a winmain16 e il codice è stato compilato.

Modifica: vale anche la pena controllare le impostazioni di build all'interno del tuo IDE.

(Non sono sicuro che questo errore sia correlato al recente aggiornamento dell'IDE - potrebbe essere causale o semplicemente correlativo. Sentiti libero di commentare con qualsiasi intuizione su quel fattore!)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.