การอ้างอิงที่ไม่ได้กำหนดถึง `` WinMain @ 16 ''


110

เมื่อฉันพยายามสร้างโปรแกรมโดยใช้Eclipse CDTฉันจะได้รับสิ่งต่อไปนี้:

/mingw/lib/libmingw32.a(main.o):main.c:(.text+0x106): การอ้างอิงที่ไม่ได้กำหนดถึง `WinMain @ 16

ทำไมถึงเป็นเช่นนั้น? และฉันจะแก้ปัญหานี้ได้อย่างไร

คำตอบ:


184

พิจารณาโปรแกรมระดับ Windows API ต่อไปนี้:

#define NOMINMAX
#include <windows.h>

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

ตอนนี้มาสร้างโดยใช้ GNU toolchain (เช่น g ++) ไม่มีตัวเลือกพิเศษ นี่gnucเป็นเพียงไฟล์แบตช์ที่ฉันใช้สำหรับสิ่งนั้น มีเพียงตัวเลือกเพื่อทำให้ g ++ เป็นมาตรฐานมากขึ้น:

C: \ test> gnuc x.cpp

C: \ test> objdump -x a.exe | findstr / i "^ ระบบย่อย"
ระบบย่อย 00000003 (Windows CUI)

C: \ test> _

ซึ่งหมายความว่าโดยดีฟอลต์ตัวเชื่อมสร้างระบบย่อยคอนโซลที่เรียกใช้งานได้ ระบบย่อยค่าในส่วนหัวของแฟ้มบอกสิ่งที่ให้บริการของ Windows โปรแกรมต้อง ในกรณีนี้กับระบบคอนโซลโปรแกรมต้องใช้หน้าต่างคอนโซล

นอกจากนี้ยังทำให้ตัวแปลคำสั่งรอให้โปรแกรมทำงานให้เสร็จสมบูรณ์

ทีนี้มาสร้างด้วยระบบย่อย GUIซึ่งหมายความว่าโปรแกรมไม่ต้องการหน้าต่างคอนโซล:

C: \ test> gnuc x.cpp -mwindows

C: \ test> objdump -x a.exe | findstr / i "^ ระบบย่อย"
ระบบย่อย 00000002 (Windows GUI)

C: \ test> _

หวังว่าจะเป็นอย่างนั้นแม้ว่า-mwindowsแฟล็กจะเป็นเพียงเอกสารกึ่งเอกสาร

การสร้างโดยไม่มีแฟล็กกึ่งเอกสารนั้นจะต้องบอกผู้เชื่อมโยงให้มากขึ้นว่าระบบย่อยต้องการค่าใดและโดยทั่วไปแล้วไลบรารีการนำเข้า Windows API บางไลบรารีจะต้องระบุอย่างชัดเจน:

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

C: \ test> objdump -x a.exe | findstr / i "^ ระบบย่อย"
ระบบย่อย 00000002 (Windows GUI)

C: \ test> _

มันใช้งานได้ดีด้วย GNU toolchain

แต่ Microsoft toolchain เช่น Visual C ++ ล่ะ?

การสร้างเป็นระบบย่อยคอนโซลที่เรียกใช้งานได้ดี:

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

C: \ test> dumpbin / headers x.exe | ค้นหา / i "ระบบย่อย" | ค้นหา / i "Windows"
               3 ระบบย่อย (Windows CUI)

C: \ test> _

อย่างไรก็ตามด้วยการสร้าง toolchain ของ Microsoft เนื่องจากระบบย่อย GUI ไม่ทำงานตามค่าเริ่มต้น:

C: \ test> msvc x.cpp user32.lib / link / ระบบย่อย: windows
x.cpp
LIBCMT.lib (wincrt0.obj): ข้อผิดพลาด LNK2019: สัญลักษณ์ภายนอกที่ไม่ได้รับการแก้ไข _WinMain @ 16 ที่อ้างถึงในฟังก์ชัน ___tmainCRTStartu
น
x.exe: ข้อผิดพลาดร้ายแรง LNK1120: 1 ภายนอกที่ไม่ได้รับการแก้ไข

C: \ test> _

เทคนิคนี้เป็นเพราะลิงเกอร์ไมโครซอฟท์เป็นที่ไม่ได้มาตรฐานโดยเริ่มต้นสำหรับ GUI ระบบย่อย โดยค่าเริ่มต้นเมื่อระบบย่อยคือ GUI แล้วลิงเกอร์ไมโครซอฟท์ใช้ห้องสมุดรันไทม์จุดเข้าฟังก์ชั่นที่มีการเรียกใช้รหัสเครื่องเริ่มต้นที่เรียกwinMainCRTStartupว่าไมโครซอฟท์เรียกร้องที่ไม่ได้มาตรฐานแทนมาตรฐานWinMainmain

ไม่มีเรื่องใหญ่ที่จะแก้ไขได้

สิ่งที่คุณต้องทำคือบอกผู้เชื่อมโยงของ Microsoft ว่าจะใช้จุดเข้าใช้งานmainCRTStartupใดซึ่งเรียกว่ามาตรฐานmain:

C: \ test> msvc x.cpp user32.lib / link / ระบบย่อย: windows / entry: mainCRTStartup
x.cpp

C: \ test> dumpbin / headers x.exe | ค้นหา / i "ระบบย่อย" | ค้นหา / i "Windows"
               2 ระบบย่อย (Windows GUI)

C: \ test> _

ไม่มีปัญหา แต่น่าเบื่อมาก และมีความลับและซ่อนอยู่ทำให้โปรแกรมเมอร์ Windows ส่วนใหญ่ซึ่งส่วนใหญ่ใช้เฉพาะเครื่องมือที่ไม่ได้มาตรฐานโดยค่าเริ่มต้นของ Microsoft ไม่รู้ด้วยซ้ำและเข้าใจผิดคิดว่าโปรแกรมระบบย่อย Windows GUI“ ต้อง” ไม่ได้มาตรฐานWinMainแทนที่จะเป็นมาตรฐานmain. ในการส่งผ่าน C ++ 0x Microsoft จะมีปัญหากับสิ่งนี้เนื่องจากคอมไพเลอร์จะต้องโฆษณาว่าเป็นแบบอิสระหรือโฮสต์ (เมื่อโฮสต์ต้องรองรับมาตรฐานmain)

อย่างไรก็ตามนั่นเป็นเหตุผลที่ g ++ สามารถบ่นว่าWinMainหายไป: มันเป็นฟังก์ชั่นการเริ่มต้นที่ไม่ได้มาตรฐานโง่ ๆ ที่เครื่องมือของ Microsoft ต้องการโดยค่าเริ่มต้นสำหรับโปรแกรมระบบย่อย GUI

แต่อย่างที่คุณเห็นด้านบน g ++ ไม่มีปัญหากับมาตรฐานmainแม้แต่กับโปรแกรมระบบย่อย GUI

แล้วปัญหาอาจเกิดจากอะไร?

คุณอาจจะพลาดไฟล์main. และคุณอาจไม่มี (เหมาะสม) WinMainเช่นกัน! จากนั้น g ++ หลังจากค้นหาmain(ไม่เป็นเช่นนั้น) และสำหรับ Microsoft ที่ไม่ได้มาตรฐานWinMain(ไม่เป็นเช่นนั้น) รายงานว่าส่วนหลังหายไป

การทดสอบด้วยแหล่งที่ว่าง:

C: \ test> พิมพ์ nul> y.cpp

C: \ test> gnuc y.cpp -mwindows
c: / ไฟล์โปรแกรม / mingw / bin /../ lib / gcc / mingw32 / 4.4.1 /../../../ libmingw32.a (main.o): main.c :(. text + 0xd2 ): การอ้างอิงที่ไม่ได้กำหนด
ไปที่ `` WinMain @ 16 ''
collect2: ld ส่งคืนสถานะการออก 1 ครั้ง

C: \ test> _

3
@ อัลฟ. สไตน์บัค. ขอบคุณมากสำหรับคำตอบที่ดีของคุณ สำหรับAll you have to do is to tell Microsoft's linker which entry point to use, namely mainCRTStartup, which calls standard main. มีวิธีทำEclipse CDTไหมเนื่องจากฉันไม่ได้ใช้บรรทัดคำสั่ง ขอบคุณ
Simplicity

1
@ user588855: เนื่องจากคุณใช้ g ++ ซึ่ง (อาจ) ใช้ไม่ได้กับคุณ ใช้เฉพาะส่วนท้าย (อาจ) เท่านั้น นั่นคือกำหนด a mainหรือ a WinMainหรือตรวจสอบให้แน่ใจว่าไฟล์ที่เกี่ยวข้องรวมอยู่ในโครงการ ไชโย
ไชโยและ hth - Alf

@ อัลฟ. สไตน์บัค. นิยามหมายถึงอะไรmainหรือwinmain? ขอบคุณ
เรียบง่าย

1
ฉันเพิ่งสร้างไฟล์ชื่อ main.cpp ที่มีรหัส: int main () {}
แน่นอน

3
ฉันคงจะดีถ้าผู้โหวตแต่ละคนสามารถอธิบายการโหวตลดได้ สำหรับผู้อ่านคนอื่น ๆ อาจมีความเข้าใจผิดแบบเดียวกัน (ไม่ว่าจะเป็นอะไรก็ตาม) แล้วเราก็สามารถเคลียร์เรื่องนี้ได้ ทุกคนจะได้รับประโยชน์แทนที่จะถูกบางคนเข้าใจผิด ดังนั้นโปรดอธิบายการลงคะแนนของคุณ ขอบคุณ.
ไชโยและ hth - Alf

68

เพื่อสรุปโพสต์ข้างต้นโดย Cheers and hth - Alf ตรวจสอบให้แน่ใจว่าคุณมีmain()หรือWinMain()กำหนดไว้และ g ++ ควรทำในสิ่งที่ถูกต้อง

ปัญหาของฉันคือmain()ถูกกำหนดไว้ภายในเนมสเปซโดยบังเอิญ


เพิ่งตระหนักถึงบางสิ่งที่สำคัญเกี่ยวกับทั้งหมดนี้ ในกรณีของฉันมันไม่พบ main () เนื่องจากฉันไม่ได้ประกาศข้อโต้แย้งใด ๆ (argc, argv) เมื่อเพิ่มแล้วพบว่าหลัก นอกจากนี้ลักษณะของวิธีการทำงานนี้หมายความว่า mingw พยายามช่วยโดยจัดหาหลักของตัวเองซึ่งจะเรียก WinMain โปรแกรม GUI จะมีเฉพาะ WinMain และใช้ต้นขั้วหลักใน mingw เพื่อไปที่นั่น หากคุณมีหลักก็ใช้สิ่งนั้นแทน
Jeff Muir

extern "C" int main (เป็นโมฆะ) แก้ไขปัญหาให้ฉัน
dryler

33

ฉันพบข้อผิดพลาดนี้ขณะคอมไพล์แอปพลิเคชันด้วย SDL สิ่งนี้เกิดจาก SDL กำหนดฟังก์ชันหลักของตัวเองใน SDL_main.h เพื่อป้องกันไม่ให้ SDL กำหนดฟังก์ชันหลักจำเป็นต้องกำหนดมาโคร SDL_MAIN_HANDLED ก่อนที่จะรวมส่วนหัว SDL.h


ตอบโจทย์มาก! +1
Mohammad Kanan

ขอบคุณมาก! คำสั่งนี้ใช้ได้: 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

ลองบันทึกไฟล์. c ของคุณก่อนสร้าง ฉันเชื่อว่าคอมพิวเตอร์ของคุณอ้างอิงเส้นทางไปยังไฟล์ที่ไม่มีข้อมูลอยู่ภายใน

- มีปัญหาที่คล้ายกันเมื่อสร้างโครงการ C


วิธีนี้ช่วยแก้ปัญหาของฉันได้จริงและฉันจะแสดงความคิดเห็นนี้เพื่อช่วยให้ได้รับความสนใจมากขึ้น
David Chen

0

ตรวจสอบว่าไฟล์ทั้งหมดรวมอยู่ในโครงการของคุณ:

ฉันมีข้อผิดพลาดเดียวกันนี้ปรากฏขึ้นหลังจากที่ฉันอัปเดต cLion หลังจากผ่านไปหลายชั่วโมงฉันสังเกตเห็นว่าไฟล์หนึ่งของฉันไม่ได้รวมอยู่ในเป้าหมายโครงการ หลังจากที่ฉันเพิ่มกลับเข้าไปในโปรเจ็กต์ที่ใช้งานอยู่ฉันหยุดรับข้อมูลอ้างอิงที่ไม่ได้กำหนดไปยัง winmain16 และรวบรวมโค้ดแล้ว

แก้ไข: ควรตรวจสอบการตั้งค่าการสร้างภายใน IDE ของคุณด้วย

(ไม่แน่ใจว่าข้อผิดพลาดนี้เกี่ยวข้องกับการอัปเดต IDE เมื่อเร็ว ๆ นี้ - อาจเป็นสาเหตุหรือสัมพันธ์กันเพียงแค่แสดงความคิดเห็นพร้อมข้อมูลเชิงลึกเกี่ยวกับปัจจัยนั้น ๆ !)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.