การประกาศหลักที่เหมาะสมคืออะไร?


147

ลายเซ็นที่เหมาะสมของmainฟังก์ชั่นใน C ++ คืออะไร? ประเภทผลตอบแทนที่ถูกต้องคืออะไรและการคืนค่ามาจากmainอะไร ประเภทพารามิเตอร์ที่อนุญาตคืออะไรและมีความหมายอย่างไร

นี่เป็นระบบเฉพาะหรือไม่ กฎเหล่านั้นเปลี่ยนไปตามกาลเวลาหรือไม่? จะเกิดอะไรขึ้นถ้าฉันละเมิดพวกเขา


1
นี้จะเกี่ยวข้องอย่างใกล้ชิดกับหรือซ้ำกันของสิ่งที่ควรmainกลับมาใน C และ C
Jonathan Leffler

@JonathanLeffler ไม่มีการล้อเล่น ... มันถูกเพิ่มเข้าไปในรายการซ้ำในการแก้ไข 6ประมาณ 8 เดือนที่ผ่านมา
fredoverflow

คำตอบ:


192

mainต้องประกาศฟังก์ชันนี้เป็นฟังก์ชันที่ไม่ใช่สมาชิกในเนมสเปซส่วนกลาง ซึ่งหมายความว่ามันไม่สามารถเป็นฟังก์ชันสมาชิกแบบคงที่หรือไม่คงที่ของคลาสและไม่สามารถวางในเนมสเปซ (แม้แต่เนมสเปซที่ไม่มีชื่อ)

ชื่อmainไม่ได้ถูกสงวนไว้ใน C ++ ยกเว้นเป็นฟังก์ชันในเนมสเปซส่วนกลาง คุณสามารถประกาศเอนทิตีอื่น ๆ ที่มีชื่อmainรวมถึงสิ่งอื่น ๆ คลาสตัวแปรการแจกแจงฟังก์ชันสมาชิกและฟังก์ชันที่ไม่ใช่สมาชิกไม่ได้อยู่ในเนมสเปซส่วนกลาง

คุณสามารถประกาศฟังก์ชั่นที่ชื่อว่าmainเป็นฟังก์ชั่นสมาชิกหรือในเนมสเปซ แต่ฟังก์ชั่นดังกล่าวจะไม่เป็นmainฟังก์ชั่นที่กำหนดว่าโปรแกรมจะเริ่มต้นที่ใด

mainฟังก์ชั่นไม่สามารถประกาศเป็นหรือstatic inlineมันไม่สามารถรับได้มากเกินไป สามารถมีฟังก์ชันได้เพียงชื่อเดียวmainในเนมสเปซส่วนกลาง

mainฟังก์ชั่นนี้ไม่สามารถใช้ในโปรแกรมของคุณ: คุณไม่ได้รับอนุญาตให้เรียกmainฟังก์ชั่นได้จากทุกที่ในรหัสของคุณหรือคุณได้รับอนุญาตให้ใช้ที่อยู่ของ

ประเภทการกลับมาของmainintต้อง ไม่อนุญาตให้ใช้ชนิดส่งคืนอื่น ๆ (กฎนี้เป็นตัวหนาเนื่องจากเป็นเรื่องปกติมากที่จะเห็นโปรแกรมที่ไม่ถูกต้องที่ประกาศmainด้วยชนิดส่งคืนvoidซึ่งอาจเป็นกฎที่ละเมิดบ่อยที่สุดเกี่ยวกับmainฟังก์ชัน)

ต้องมีการประกาศสองรายการmainที่ต้องได้รับอนุญาต:

int main()               // (1)
int main(int, char*[])   // (2)

ใน(1)ไม่มีพารามิเตอร์

ใน(2)มีสองพารามิเตอร์และพวกเขาจะตั้งชื่อตามอัตภาพargcและargvตามลำดับ argvเป็นตัวชี้ไปยังอาร์เรย์ของสตริง C ซึ่งแทนอาร์กิวเมนต์ของโปรแกรม argcคือจำนวนอาร์กิวเมนต์ในargvอาร์เรย์

โดยปกติแล้วจะargv[0]มีชื่อของโปรแกรม แต่นี่ไม่ใช่กรณี argv[argc]รับประกันว่าจะเป็นตัวชี้โมฆะ

โปรดทราบว่าเนื่องจากอาร์กิวเมนต์ประเภทอาเรย์ (เหมือนchar*[]) เป็นเพียงอาร์กิวเมนต์ประเภทพอยน์เตอร์ในการปลอมตัวทั้งสองต่อไปนี้เป็นวิธีที่ถูกต้องในการเขียน(2)และพวกเขาทั้งสองมีความหมายเหมือนกันทั้งหมด:

int main(int argc, char* argv[])
int main(int argc, char** argv)

การใช้งานบางอย่างอาจอนุญาตประเภทและจำนวนพารามิเตอร์อื่น ๆ คุณต้องตรวจสอบเอกสารการติดตั้งเพื่อดูว่ารองรับอะไรบ้าง

main()คาดว่าจะคืนค่าศูนย์เพื่อระบุความสำเร็จและไม่เป็นศูนย์เพื่อระบุความล้มเหลว คุณไม่จำเป็นต้องชัดเจนเขียนreturnคำสั่งในmain(): ถ้าคุณให้main()กลับมาโดยไม่ต้องชัดเจนคำสั่งก็เหมือนกันเช่นถ้าคุณได้เขียนreturn return 0;สองmain()ฟังก์ชันต่อไปนี้มีพฤติกรรมเหมือนกัน:

int main() { }
int main() { return 0; }

มีมาโครสองตัวEXIT_SUCCESSและEXIT_FAILUREกำหนดไว้ใน<cstdlib>ที่สามารถส่งคืนจากmain()เพื่อบ่งชี้ความสำเร็จและความล้มเหลวตามลำดับ

ค่าที่ส่งคืนโดยmain()ถูกส่งผ่านไปยังexit()ฟังก์ชันซึ่งจะยกเลิกโปรแกรม

โปรดทราบว่าทั้งหมดนี้ใช้เฉพาะเมื่อรวบรวมสำหรับสภาพแวดล้อมที่โฮสต์ (ไม่เป็นทางการซึ่งเป็นสภาพแวดล้อมที่คุณมีห้องสมุดมาตรฐานเต็มรูปแบบและมีระบบปฏิบัติการที่รันโปรแกรมของคุณ) นอกจากนี้ยังเป็นไปได้ที่จะรวบรวมโปรแกรม C ++ สำหรับสภาพแวดล้อมอิสระ (ตัวอย่างเช่นระบบฝังตัวบางประเภท) ซึ่งในกรณีนี้การเริ่มต้นและการเลิกจ้างจะถูกกำหนดโดยการนำไปปฏิบัติทั้งหมดและmain()อาจไม่จำเป็นต้องใช้ฟังก์ชั่น หากคุณกำลังเขียน C ++ สำหรับเดสก์ท็อประบบปฏิบัติการสมัยใหม่คุณกำลังรวบรวมสภาพแวดล้อมที่โฮสต์


1
IIRC ค่าส่งคืนที่รับประกันเท่านั้นคือ 0, EXIT_SUCCESS (เอฟเฟกต์เดียวกับ 0) และ EXIT_FAILURE แก้ไข: Ah, OK, ค่าสถานะอื่น ๆ ที่ไม่ใช่ศูนย์อาจถูกส่งกลับ แต่มีความหมายที่กำหนดใช้งาน EXIT_FAILURE เท่านั้นที่รับประกันว่าจะตีความในบางวิธีเป็นค่าความล้มเหลว
Derrick Turk

4
@Synetech: คำถามที่ถามในประโยคแรกของมันคือ "ลายเซ็นที่เหมาะสมของฟังก์ชั่นหลักใน C ++ คืออะไร" และคำถามจะถูกแท็กทั้ง [c ++] และ [c ++ - faq] ฉันไม่สามารถช่วยได้หากผู้ใช้ Java หรือ C # (หรือคนอื่น) ยังคงสับสน C # ต้องMainเป็นฟังก์ชันสมาชิกแบบคงที่เนื่องจากไม่มีฟังก์ชันที่ไม่ใช่สมาชิก แม้ C89 ต้องที่จะกลับมาmain intฉันไม่คุ้นเคยกับ K&R C เพียงพอที่จะรู้กฎที่แน่นอนของมัน แต่ฉันเดาว่ามันต้องมีmainการส่งคืนintเนื่องจากmainไม่มีประเภทการส่งคืนค่อนข้างทั่วไปและไม่มี type = นัยintใน K&R
James McNellis

3
@Suhail: intเพราะมาตรฐานภาษาพูดประเภทกลับจะเป็น
James McNellis

1
@Suhail: ใช่ รหัสของคุณจะไม่ถูกต้อง C ++ และคอมไพเลอร์จำนวนมากจะปฏิเสธรหัสของคุณ
James McNellis

2
@Suhail: Visual C ++ อนุญาตให้voidพิมพ์กลับเป็นส่วนขยายของภาษา คอมไพเลอร์ที่ไม่อนุญาตรวมถึง GCC และ Comeau
James McNellis

15

จากเอกสารมาตรฐาน. 3.6.1.2 ฟังก์ชั่นหลัก ,

มันจะต้องมีชนิดผลตอบแทนประเภท int แต่มิฉะนั้นประเภทของมันคือการดำเนินการที่กำหนดไว้ การใช้งานทั้งหมดจะต้องอนุญาตทั้งคำจำกัดความหลักดังต่อไปนี้:

int main() { / ... / } และ int main(int argc, char* argv[]) { / ... / }

ในรูปแบบหลังargcจะเป็นจำนวนของข้อโต้แย้งที่ส่งผ่านไปยังโปรแกรมจากสภาพแวดล้อมที่โปรแกรมจะทำงานหาก argc ไม่ใช่ศูนย์อาร์กิวเมนต์เหล่านี้จะถูกจัดทำใน argv [0] ผ่าน argv [argc-1] เป็นตัวชี้ไปเริ่มต้น อักขระของสตริงหลายไบต์ที่สิ้นสุดด้วยค่า null .....

หวังว่าจะช่วย ..


2
มีเหตุผลเฉพาะว่าทำไมประเภทการคืนสินค้าmainควรเป็นintอย่างไร
Suhail Gupta

1
@SuhailGupta: เพื่อให้กระบวนการเรียกรู้ว่ากระบวนการนี้ควรจะถือว่าประสบความสำเร็จหรือไม่ อนุญาตให้voidแบ่งรูปแบบนั้น มันไม่สมเหตุสมผลเลยถ้าคุณมีความหมายว่า "ถือว่าประสบความสำเร็จเสมอ" เพราะคุณมีวิธีการบอกว่าถ้ากระบวนการล้มเหลวจริงไม่ดังนั้นคุณไม่ได้จริงๆประสบความสำเร็จ? intไม่มีผลตอบแทน
การแข่งขัน Lightness ใน Orbit

4

ถ้อยคำที่แน่นอนของมาตรฐานที่เผยแพร่ล่าสุด (C ++ 14) คือ:

การดำเนินการจะช่วยให้ทั้งสอง

  • ฟังก์ชั่นการ()กลับมาintและ

  • ฟังก์ชั่นของ(int, ตัวชี้ไปยังตัวชี้เพื่อchar)กลับint

mainเป็นประเภทของ

นี้จะทำให้มันชัดเจนว่าการสะกดทางเลือกที่ได้รับอนุญาตตราบเท่าที่ประเภทของการmainเป็นชนิดหรือint() int(int, char**)ดังนั้นสิ่งต่อไปนี้จะได้รับอนุญาตด้วย:

  • int main(void)
  • auto main() -> int
  • int main ( )
  • signed int main()
  • typedef char **a; typedef int b, e; e main(b d, a c)

1
NB ฉันโพสต์คำตอบนี้ตามความเห็นในเธรดอื่นมีคนพยายามอ้างอิงหัวข้อนี้เป็นหลักฐานที่int main(void)ไม่ถูกต้องใน C ++
MM

3
@Stargateur auto main() -> intไม่มีประเภทผลตอบแทนที่อนุมาน ให้ความสนใจกับ {ใน "(ไม่อนุญาตให้ใช้หลักอัตโนมัติ () {... )" และโปรดเรียนรู้ที่จะรู้เมื่อคุณยังไม่พอที่จะเพิ่มสิ่งที่มีความหมาย

3

ทั้งสองไฟที่ถูกต้องและint main() int main(int, char*[])สิ่งอื่นใดอาจหรือไม่รวบรวม หากmainไม่ส่งคืนค่าอย่างชัดเจน0จะถูกส่งกลับโดยปริยาย


1
ฉันไม่เคยเห็นรหัสที่ไม่ได้รับการคอมไพล์เมื่อฉันกล่าวถึงประเภทการคืนค่าmainให้เป็นโมฆะ มีเหตุผลใดที่เฉพาะเจาะจงที่ประเภทการคืนของหลักควรเป็น int หรือไม่?
Suhail Gupta

4
ข้อมูลจำเพาะเกี่ยวกับภาษาบอกว่า main ต้องมีชนิด return ของ int ประเภทผลตอบแทนอื่น ๆ ที่คอมไพเลอร์ของคุณอนุญาตเป็นการปรับปรุงเฉพาะคอมไพเลอร์ โดยทั่วไปใช้โมฆะหมายความว่าคุณกำลังเขียนโปรแกรมในภาษาที่คล้ายกับ แต่ไม่ใช่ C ++
หิน

2
เหตุผลมาตรฐานต้องมีintเป็นประเภทผลตอบแทนของmainคือการที่ค่านี้ถูกส่งไปยังเปลือกเป็นรหัสที่ออกจากโปรแกรมและคาดว่าจะมีsh int
uckelman

อาจเป็นเพราะมีระเบียบวินัยหรือไม่ อาจมีเส้นทางมากกว่าหนึ่งเส้นทาง หากประเภทการคืนสินค้าเป็นvoidแบบเงียบทั้งหมด ด้วยintเราจะต้องกำหนดค่าทางออกเฉพาะสำหรับการกลับมาแต่ละmainครั้ง
Andreas Spindler

2

รายละเอียดเกี่ยวกับค่าตอบแทนและความหมาย

ต่อ 3.6.1 ( [basic.start.main]):

คำสั่ง return ในmainมีผลต่อการออกจากmainฟังก์ชั่น (ทำลายวัตถุใด ๆ ที่มีระยะเวลาการจัดเก็บอัตโนมัติ) และการโทรstd::exitด้วยค่าตอบแทนเป็นอาร์กิวเมนต์ หากการควบคุมถึงจุดสิ้นสุดmainโดยไม่ต้องเผชิญกับreturnคำสั่งผลกระทบก็คือการดำเนินการ

return 0;

พฤติกรรมของstd::exitมีรายละเอียดในส่วนที่ 18.5 ( [support.start.term]) และอธิบายรหัสสถานะ:

ในที่สุดการควบคุมจะถูกส่งกลับไปยังสภาพแวดล้อมโฮสต์ หากสถานะเป็นศูนย์หรือEXIT_SUCCESSมีการส่งคืนฟอร์มที่กำหนดโดยการนำไปปฏิบัติของสถานะการยกเลิกสำเร็จ หากสถานะเป็นEXIT_FAILUREแบบฟอร์มการดำเนินการที่กำหนดไว้ของสถานะการยกเลิกไม่สำเร็จจะถูกส่งกลับ มิฉะนั้นสถานะที่ส่งคืนจะถูกกำหนดโดยการนำไปปฏิบัติ

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