เป็น 'int main; โปรแกรม C / C ++ ที่ถูกต้องหรือไม่


113

ฉันถามเพราะดูเหมือนว่าคอมไพเลอร์ของฉันจะคิดอย่างนั้นแม้ว่าฉันจะไม่ทำก็ตาม

echo 'int main;' | cc -x c - -Wall
echo 'int main;' | c++ -x c++ - -Wall

เสียงดังรบกวนไม่มีคำเตือนหรือข้อผิดพลาดเกี่ยวกับสิ่งนี้และ gcc จะออกเฉพาะคำเตือนที่อ่อนโยน: 'main' is usually a function [-Wmain]แต่เฉพาะเมื่อรวบรวมเป็น C การระบุ a -std=ดูเหมือนจะไม่สำคัญ

มิฉะนั้นจะรวบรวมและเชื่อมโยงได้ดี แต่ในการดำเนินการมันจะสิ้นสุดลงทันทีด้วยSIGBUS(สำหรับฉัน)

การอ่านคำตอบ (ยอดเยี่ยม) ที่สิ่งที่ main () ควรส่งคืนใน C และ C ++? และ grep อย่างรวดเร็วผ่านข้อกำหนดภาษาดูเหมือนว่าฉันจะต้องมีฟังก์ชันหลักอย่างแน่นอน แต่คำฟุ่มเฟือยจาก gcc -Wmain('main' มักจะเป็นฟังก์ชัน) (และข้อผิดพลาดที่นี่) ดูเหมือนจะแนะนำเป็นอย่างอื่น

แต่ทำไม? มีการใช้ edge-case แปลก ๆ หรือ“ ประวัติศาสตร์” สำหรับสิ่งนี้หรือไม่? ใครรู้บ้างว่าให้?

ประเด็นของฉันฉันคิดว่าฉันคิดว่านี่น่าจะเป็นข้อผิดพลาดในสภาพแวดล้อมที่โฮสต์ใช่ไหม


6
ในการสร้างคอมไพเลอร์มาตรฐาน gcc a (ส่วนใหญ่) คุณต้องgcc -std=c99 -pedantic ...
pmg

3
@pmg คำเตือนเดียวกันมันมีหรือไม่มีหรือ-pedantic -stdระบบของฉันc99ยังรวบรวมสิ่งนี้โดยไม่มีคำเตือนหรือข้อผิดพลาด ...
Geoff Nixon

3
น่าเสียดายถ้าคุณ "ฉลาดพอ" คุณสามารถสร้างสิ่งต่างๆที่คอมไพเลอร์ยอมรับได้ แต่ไม่สมเหตุสมผล ในกรณีนี้คุณกำลังเชื่อมโยงไลบรารีรันไทม์ C เพื่อเรียกตัวแปรที่เรียกว่าmainซึ่งไม่น่าจะทำงานได้ หากคุณเริ่มต้น main ด้วยค่าที่ "ถูกต้อง" มันอาจจะกลับมา ...
Mats Petersson

7
และแม้ว่าจะถูกต้อง แต่ก็เป็นสิ่งที่น่ากลัวที่ต้องทำ (รหัสที่อ่านไม่ได้) BTW อาจแตกต่างกันในการใช้งานแบบโฮสต์และในการใช้งานแบบอิสระ (ซึ่งไม่ทราบmain)
Basile Starynkevitch

1
เพื่อความสนุกสนานมากขึ้นลองmain=195;
imallett

คำตอบ:


97

เนื่องจากคำถามถูกแท็กสองครั้งเป็น C และ C ++ เหตุผลของ C ++ และ C จึงแตกต่างกัน:

  • C ++ ใช้ชื่อ mangling เพื่อช่วยให้ตัวเชื่อมโยงแยกแยะระหว่างสัญลักษณ์ที่เหมือนกันตามข้อความของประเภทต่างๆเช่นตัวแปรส่วนกลางxyzและฟังก์ชันโกลบอลที่มีสถานะxyz(int)อิสระ อย่างไรก็ตามชื่อmainไม่เคยแหลกเหลว
  • C ไม่ใช้ mangling ดังนั้นจึงเป็นไปได้ที่โปรแกรมจะสร้างความสับสนให้กับตัวเชื่อมโยงโดยการให้สัญลักษณ์ชนิดหนึ่งแทนสัญลักษณ์อื่นและให้โปรแกรมเชื่อมโยงสำเร็จ

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

นี่คือภาพประกอบอื่นของปัญหาเดียวกัน:

ไฟล์ xc:

#include <stdio.h>
int foo(); // <<== main() expects this
int main(){
    printf("%p\n", (void*)&foo);
    return 0;
}

ไฟล์ yc:

int foo; // <<== external definition supplies a symbol of a wrong kind

รวบรวม:

gcc x.c y.c

คอมไพเลอร์นี้และมันอาจจะทำงาน แต่เป็นพฤติกรรมที่ไม่ได้กำหนดเนื่องจากชนิดของสัญลักษณ์ที่สัญญาไว้กับคอมไพเลอร์นั้นแตกต่างจากสัญลักษณ์จริงที่ให้ไว้กับตัวเชื่อมโยง

เท่าที่มีคำเตือนฉันคิดว่ามันสมเหตุสมผล: C ช่วยให้คุณสร้างไลบรารีที่ไม่มีmainฟังก์ชันดังนั้นคอมไพเลอร์จึงปล่อยชื่อmainสำหรับการใช้งานอื่น ๆ หากคุณต้องการกำหนดตัวแปรmainด้วยเหตุผลที่ไม่ทราบสาเหตุ


3
แม้ว่าคอมไพเลอร์ C ++ จะปฏิบัติหน้าที่หลักแตกต่างกัน ชื่อของมันไม่แหลกเหลวแม้ไม่มี "C" ภายนอก ฉันเดาว่าเป็นเพราะไม่เช่นนั้นมันจะต้องปล่อยเป็น "C" main ภายนอกของตัวเองเพื่อให้แน่ใจว่ามีการเชื่อมโยง
UldisK

@UldisK ใช่ฉันสังเกตตัวเองและพบว่าน่าสนใจทีเดียว มันสมเหตุสมผล แต่ฉันไม่เคยคิดเรื่องนั้นมาก่อน
Geoff Nixon

2
อันที่จริงผลลัพธ์ของ C ++ และ C ไม่แตกต่างกันดังที่ได้ระบุไว้ที่นี่ - mainไม่ได้ขึ้นอยู่กับการโกงชื่อ (ดังนั้นจึงดูเหมือน) ใน C ++ ไม่ว่าจะเป็นฟังก์ชันหรือไม่ก็ตาม
Geoff Nixon

4
@nm ฉันคิดว่าการตีความคำถามของคุณแคบเกินไป: นอกเหนือจากการถามคำถามในชื่อโพสต์แล้ว OP ยังหาคำอธิบายอย่างชัดเจนว่าเหตุใดโปรแกรมของเขาจึงรวบรวมตั้งแต่แรก ("คอมไพเลอร์ของฉันดูเหมือนจะคิดอย่างนั้น แม้ว่าฉันจะไม่ ") รวมทั้งคำแนะนำว่าเหตุใดจึงมีประโยชน์ในการกำหนดmainเป็นสิ่งอื่นที่ไม่ใช่ฟังก์ชัน คำตอบมีคำอธิบายสำหรับทั้งสองส่วน
dasblinkenlight

1
การที่สัญลักษณ์ main ไม่อยู่ภายใต้การโกงชื่อนั้นไม่เกี่ยวข้อง ไม่มีการกล่าวถึงการโกงกินชื่อในมาตรฐาน C ++ การโกงชื่อเป็นปัญหาในการนำไปใช้งาน
David Hammen

30

mainไม่ได้เป็นคำสงวนเป็นเพียงตัวบ่งชี้ที่กำหนดไว้ล่วงหน้า (เช่นcin, endl, npos... ) เพื่อให้คุณสามารถประกาศตัวแปรที่เรียกว่าmain, เริ่มต้นมันแล้วพิมพ์ออกมาคุ้มค่า

แน่นอน:

  • คำเตือนมีประโยชน์เนื่องจากมีข้อผิดพลาดค่อนข้างง่าย
  • คุณสามารถมีไฟล์ต้นฉบับโดยไม่ต้องใช้main()ฟังก์ชัน (ไลบรารี)

แก้ไข

ข้อมูลอ้างอิงบางส่วน:

  • main ไม่ใช่คำสงวน (C ++ 11):

    ห้ามใช้ฟังก์ชันนี้mainภายในโปรแกรม การเชื่อมโยง (3.5) ของmainเป็นการกำหนดการนำไปใช้งาน โปรแกรมที่กำหนดหลักที่ถูกลบหรือว่าประกาศหลักจะเป็นinline, staticหรือ constexprป่วยที่เกิดขึ้น ไม่สงวนชื่อไว้mainเป็นอย่างอื่น [ตัวอย่าง: ฟังก์ชันสมาชิกคลาสและการแจงนับสามารถเรียกใช้ได้mainเช่นเดียวกับเอนทิตีในเนมสเปซอื่น - ตัวอย่างตอนท้าย]

    C ++ 11 - [basic.start.main] 3.6.1.3

    [2.11 / 3] [... ] ตัวระบุบางตัวสงวนไว้สำหรับการใช้งานโดยการใช้งาน C ++ และไลบรารีมาตรฐาน (17.6.4.3.2) และจะไม่ใช้เป็นอย่างอื่น ไม่จำเป็นต้องมีการวินิจฉัย

    [17.6.4.3.2 / 1]ชุดชื่อและลายเซ็นฟังก์ชันบางชุดจะสงวนไว้สำหรับการนำไปใช้งานเสมอ:

    • ชื่อแต่ละชื่อที่มีขีดล่างคู่ __ หรือขึ้นต้นด้วยขีดล่างตามด้วยอักษรตัวพิมพ์ใหญ่ (2.12) จะสงวนไว้สำหรับการนำไปใช้งานสำหรับการใช้งานใด ๆ
    • แต่ละชื่อที่ขึ้นต้นด้วยขีดล่างจะสงวนไว้สำหรับการนำไปใช้งานเพื่อใช้เป็นชื่อในเนมสเปซส่วนกลาง
  • คำสงวนในภาษาโปรแกรมคำสงวนสิทธิ์ในการเขียนโปรแกรมภาษา

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


- ฉันเดาว่าฉันค่อนข้างถูกหลอกโดยข้อเท็จจริงที่ว่า (เนื่องจากมีข้อผิดพลาดมาก) เหตุใดจึงเป็นคำเตือน (ไม่ใช่ข้อผิดพลาด) และเหตุใดจึงเป็นเพียงคำเตือนเมื่อคอมไพล์เป็น C - แน่นอนว่าคุณสามารถรวบรวมได้โดยไม่ต้องmain()ฟังก์ชั่น แต่คุณไม่สามารถเชื่อมโยงว่าเป็นโปรแกรมที่ สิ่งที่เกิดขึ้นที่นี่คือมีการเชื่อมโยงโปรแกรมที่ "ถูกต้อง" โดยไม่มีmain()เพียงกmain.
Geoff Nixon

7
cinและendlไม่ได้อยู่ในเนมสเปซเริ่มต้น - อยู่ในstdเนมสเปซ nposเป็นสมาชิกของstd::basic_string.
AnotherParker

1
main จะสงวนไว้เป็นชื่อระดับโลก ไม่มีสิ่งอื่นใดที่คุณกล่าวถึงหรือไม่mainได้กำหนดไว้ล่วงหน้า
Potatoswatter

1
ดู C ++ 14 §3.6.1และ C11 §5.1.2.2.1สำหรับข้อ จำกัด เกี่ยวกับสิ่งที่mainอนุญาตให้เป็น C ++ ระบุว่า "การใช้งานจะต้องไม่กำหนดฟังก์ชันหลักไว้ล่วงหน้า" และ C กล่าวว่า "การใช้งานประกาศว่าไม่มีต้นแบบสำหรับฟังก์ชันนี้"
Potatoswatter

@manlio: โปรดชี้แจงสิ่งที่คุณอ้างถึง สำหรับ C ธรรมดาการอ้างอิงไม่ถูกต้อง ดังนั้นฉันเดาว่ามันเป็นมาตรฐาน c ++ หรือไม่?
dhein

19

คือ int main; C ที่ถูกต้อง / C ++ โปรแกรม?

ยังไม่ชัดเจนว่าโปรแกรม C / C ++ คืออะไร

คือint main;โปรแกรม C ถูกต้อง?

ใช่. การใช้งานอิสระได้รับอนุญาตให้ยอมรับโปรแกรมดังกล่าวmainไม่จำเป็นต้องมีความหมายพิเศษใด ๆ ในสภาพแวดล้อมที่อิสระ

มันไม่ใช่ถูกต้องในสภาพแวดล้อมที่เป็นเจ้าภาพ

คือ int main;ถูกต้องโปรแกรม C ++ ได้?

เหมือนกัน

ทำไมมันพัง?

โปรแกรมไม่จำเป็นต้องเหมาะสมกับสภาพแวดล้อมของคุณ ในสภาพแวดล้อมอิสระการเริ่มต้นและการสิ้นสุดโปรแกรมและความหมายของmainการใช้งานได้กำหนดไว้

ทำไมคอมไพเลอร์เตือนฉัน

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

คือgccสภาพแวดล้อมอิสระหรือมันเป็นสภาพแวดล้อมที่เป็นเจ้าภาพ?

ใช่.

gccจัดทำ-ffreestandingแฟล็กการคอมไพล์ เพิ่มและคำเตือนจะหายไป คุณอาจต้องการใช้เมื่อสร้างเช่นเมล็ดหรือเฟิร์มแวร์

g++ไม่ได้บันทึกการตั้งค่าสถานะดังกล่าว การจัดหาดูเหมือนจะไม่มีผลกับโปรแกรมนี้ เป็นไปได้อย่างปลอดภัยที่จะสมมติว่าสภาพแวดล้อมที่จัดเตรียมโดย g ++ เป็นโฮสต์ การขาดการวินิจฉัยในกรณีนี้ถือเป็นข้อบกพร่อง


17

เป็นการเตือนเนื่องจากไม่ได้รับอนุญาตทางเทคนิค รหัสเริ่มต้นจะใช้ตำแหน่งสัญลักษณ์ของ "main" และข้ามไปยังตำแหน่งนั้นด้วยอาร์กิวเมนต์มาตรฐาน 3 รายการ (argc, argv และ envp) มันไม่ได้และในเวลาเชื่อมโยงไม่สามารถตรวจสอบได้ว่าเป็นฟังก์ชันจริงหรือแม้กระทั่งว่ามันมีอาร์กิวเมนต์เหล่านั้น นี่เป็นสาเหตุที่ int main (int argc, char ** argv) ใช้งานได้ - คอมไพเลอร์ไม่ทราบเกี่ยวกับอาร์กิวเมนต์ envp และมันก็ไม่ได้ถูกใช้และเป็น caller-cleanup

เป็นเรื่องตลกคุณสามารถทำสิ่งที่ชอบ

int main = 0xCBCBCBCB;

บนเครื่อง x86 และหากไม่สนใจคำเตือนและสิ่งที่คล้ายกันมันจะไม่เพียงแค่คอมไพล์เท่านั้น แต่ยังใช้งานได้จริงอีกด้วย

ใครบางคนที่ใช้เทคนิคนี้คล้ายกับการเขียนปฏิบัติการ (ประเภท) ที่ทำงานบนสถาปัตยกรรมหลายโดยตรง - http://phrack.org/issues/57/17.html#article นอกจากนั้นยังใช้จะชนะ IOCCC - http://www.ioccc.org/1984/mullender/mullender.c


1
"เป็นคำเตือนเนื่องจากไม่ได้รับอนุญาตทางเทคนิค" - ไม่ถูกต้องใน C ++
ไชโยและ hth - Alf

3
"อาร์กิวเมนต์มาตรฐานทั้งสาม (argc, argv และ envp)" - ที่นี่คุณอาจกำลังพูดถึงมาตรฐาน Posix
ไชโยและ hth - Alf

ในระบบของฉัน (Ubuntu 14 / x64) บรรทัดต่อไปนี้ใช้ได้กับ gcc:int main __attribute__ ((section (".text")))= 0xC3C3C3C3;
csharpfolk

@ Cheersandhth. -Alf สองตัวแรกเป็นมาตรฐานอันดับสามคือ POSIX
dascandy

9

เป็นโปรแกรมที่ถูกต้องหรือไม่?

เลขที่

ไม่ใช่โปรแกรมเนื่องจากไม่มีส่วนปฏิบัติการ

คอมไพล์ถูกต้องไหม

ใช่.

ใช้กับโปรแกรมที่ถูกต้องได้หรือไม่?

ใช่.

โค้ดที่คอมไพล์ทั้งหมดไม่จำเป็นต้องสามารถเรียกใช้งานได้จึงจะถูกต้อง ตัวอย่างคือไลบรารีแบบคงที่และแบบไดนามิก

คุณได้สร้างไฟล์ออบเจ็กต์อย่างมีประสิทธิภาพ ไม่ใช่ไฟล์ปฏิบัติการที่ถูกต้องอย่างไรก็ตามโปรแกรมอื่นสามารถเชื่อมโยงไปยังวัตถุmainในไฟล์ผลลัพธ์โดยการโหลดที่รันไทม์

นี่ควรเป็นข้อผิดพลาดหรือไม่?

ตามเนื้อผ้า C ++ อนุญาตให้ผู้ใช้ทำสิ่งต่างๆที่ดูเหมือนว่าไม่มีการใช้งานที่ถูกต้อง แต่เหมาะสมกับไวยากรณ์ของภาษา

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

ตราบเท่าที่มีความเป็นไปได้ทางทฤษฎีที่จะใช้ฟังก์ชันนี้ในโค้ดจริงจึงไม่น่าเป็นไปได้มากที่การเรียกใช้อ็อบเจ็กต์ที่ไม่ใช่ฟังก์ชันmainจะทำให้เกิดข้อผิดพลาดตามภาษา


mainมันจะสร้างสัญลักษณ์ที่มองเห็นได้จากภายนอกชื่อ โปรแกรมที่ถูกต้องซึ่งต้องมีชื่อฟังก์ชันที่มองเห็นได้ภายนอกmainจะเชื่อมโยงไปยังโปรแกรมนั้นได้อย่างไร?
Keith Thompson

@KeithThompson โหลดที่รันไทม์ จะชี้แจง.
Michael Gazonda

อาจเป็นเพราะไม่สามารถบอกความแตกต่างระหว่างประเภทสัญลักษณ์ได้ การเชื่อมโยงใช้งานได้ดี - การดำเนินการ (ยกเว้นในกรณีที่สร้างขึ้นอย่างรอบคอบ) ไม่ได้
Chris Stratton

1
@ChrisStratton: ฉันคิดว่าอาร์กิวเมนต์ของ Keith คือการเชื่อมโยงล้มเหลวเนื่องจากสัญลักษณ์ถูกกำหนดแบบทวีคูณ ... เนื่องจาก "โปรแกรมที่ถูกต้อง" จะไม่ใช่โปรแกรมที่ถูกต้องเว้นแต่จะกำหนดmainฟังก์ชัน
Ben Voigt

@BenVoigt แต่ถ้าปรากฏในไลบรารีการเชื่อมโยงจะไม่ (และอาจไม่สามารถ) ล้มเหลวได้เนื่องจากในเวลาลิงก์โปรแกรมint main;จะไม่สามารถมองเห็นคำจำกัดความได้

6

ฉันต้องการเพิ่มคำตอบที่ได้รับแล้วโดยอ้างอิงมาตรฐานภาษาจริง

เป็น 'int main; โปรแกรม C ที่ถูกต้อง?

คำตอบสั้น ๆ (ความคิดเห็นของฉัน): เฉพาะในกรณีที่การใช้งานของคุณใช้ "สภาพแวดล้อมการดำเนินการอิสระ"

คำพูดต่อไปนี้ทั้งหมดจากC11

5. สิ่งแวดล้อม

การใช้งานจะแปลไฟล์ต้นฉบับ C และเรียกใช้โปรแกรม Cในสภาพแวดล้อมระบบประมวลผลข้อมูลสองระบบซึ่งจะเรียกว่าสภาพแวดล้อมการแปลและสภาพแวดล้อมการดำเนินการ [... ]

5.1.2 สภาพแวดล้อมการดำเนินการ

มีการกำหนดสภาพแวดล้อมการดำเนินการสองแบบ: อิสระและโฮสต์ ในทั้งสองกรณีการเริ่มต้นโปรแกรมจะเกิดขึ้นเมื่อฟังก์ชัน C ที่กำหนดถูกเรียกใช้โดยสภาพแวดล้อมการดำเนินการ

5.1.2.1 สภาพแวดล้อมอิสระ

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

5.1.2.2 สภาพแวดล้อมที่โฮสต์

ไม่จำเป็นต้องจัดเตรียมสภาพแวดล้อมที่โฮสต์ แต่จะต้องเป็นไปตามข้อกำหนดต่อไปนี้หากมี

5.1.2.2.1 การเริ่มต้นโปรแกรม

ฟังก์ชั่นที่เรียกว่าโปรแกรมที่เริ่มต้นเป็นชื่อหลัก [... ] มันจะถูกกำหนดด้วยประเภทผลตอบแทนของ int และไม่มีพารามิเตอร์ [... ] หรือด้วยพารามิเตอร์สองตัว [... ] หรือเทียบเท่าหรือในลักษณะที่กำหนดการนำไปใช้งานอื่น ๆ

จากสิ่งเหล่านี้จะสังเกตเห็นสิ่งต่อไปนี้:

  • โปรแกรม C11 สามารถมีสภาพแวดล้อมการดำเนินการที่เป็นอิสระหรือโฮสต์และถูกต้อง
  • หากมีอิสระไม่จำเป็นต้องมีฟังก์ชันหลัก
  • มิฉะนั้นจะต้องมีหนึ่งกับการกลับมาของหุบเขาประเภทint

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

เป็น 'int main; โปรแกรม C ++ ที่ถูกต้องหรือไม่

คำตอบสั้น ๆ (ความคิดเห็นของฉัน): เฉพาะในกรณีที่การใช้งานของคุณใช้ "สภาพแวดล้อมการดำเนินการอิสระ"

อ้างจากC ++ 14

3.6.1 ฟังก์ชันหลัก

โปรแกรมจะต้องมีฟังก์ชันโกลบอลที่เรียกว่า main ซึ่งเป็นจุดเริ่มต้นของโปรแกรมที่กำหนดไว้ มีการกำหนดการนำไปใช้งานว่าโปรแกรมในสภาพแวดล้อมอิสระจำเป็นต้องกำหนดฟังก์ชันหลักหรือไม่ [... ] มันจะมีประเภทผลตอบแทนเป็น int แต่มิฉะนั้นประเภทของมันถูกกำหนดให้ใช้งานได้ [... ] ชื่อหลักไม่ได้สงวนไว้เป็นอย่างอื่น

ที่นี่เมื่อเทียบกับมาตรฐาน C11 ข้อ จำกัด น้อยกว่าจะใช้กับสภาพแวดล้อมการดำเนินการอิสระเนื่องจากไม่มีการกล่าวถึงฟังก์ชันการเริ่มต้นเลยในขณะที่สำหรับสภาพแวดล้อมการดำเนินการที่โฮสต์กรณีนี้ค่อนข้างเหมือนกับ C11

อีกครั้งฉันขอยืนยันว่าสำหรับกรณีที่โฮสต์รหัสของคุณไม่ใช่โปรแกรม C ++ 14 ที่ถูกต้อง แต่ฉันแน่ใจว่าเป็นกรณีอิสระ

เนื่องจากคำตอบของฉันพิจารณาเฉพาะสภาพแวดล้อมการดำเนินการฉันคิดว่าคำตอบของ dasblinkenlicht เข้ามามีบทบาทในขณะที่การโกงชื่อที่เกิดขึ้นในสภาพแวดล้อมการแปลเกิดขึ้นล่วงหน้า ที่นี่ฉันไม่แน่ใจว่ามีการปฏิบัติตามคำพูดข้างต้นอย่างเคร่งครัด


4

ประเด็นของฉันฉันคิดว่าฉันคิดว่านี่น่าจะเป็นข้อผิดพลาดในสภาพแวดล้อมที่โฮสต์ใช่ไหม

ข้อผิดพลาดเป็นของคุณ คุณไม่ได้ระบุฟังก์ชันชื่อmainที่ส่งกลับไฟล์intและพยายามใช้โปรแกรมของคุณในสภาพแวดล้อมที่โฮสต์

สมมติว่าคุณมีหน่วยคอมไพล์ที่กำหนดตัวแปรส่วนกลางที่ชื่อ mainสมมติว่าคุณมีหน่วยรวบรวมที่กำหนดตัวแปรทั่วโลกชื่อสิ่งนี้อาจเป็นสิ่งที่ถูกกฎหมายในสภาพแวดล้อมอิสระเนื่องจากสิ่งที่ประกอบขึ้นเป็นโปรแกรมนั้นเหลืออยู่สำหรับการนำไปใช้งานในสภาพแวดล้อมอิสระ

สมมติว่าคุณมีหน่วยคอมไพล์อื่นที่กำหนดฟังก์ชันโกลบอลชื่อmainที่ส่งคืน an intและไม่มีอาร์กิวเมนต์ นี่คือสิ่งที่โปรแกรมในสภาพแวดล้อมที่โฮสต์ต้องการ

ทุกอย่างจะดีถ้าคุณใช้เฉพาะหน่วยคอมไพล์แรกในสภาพแวดล้อมอิสระและใช้หน่วยที่สองในสภาพแวดล้อมที่โฮสต์เท่านั้น จะเป็นอย่างไรถ้าคุณใช้ทั้งสองอย่างในโปรแกรมเดียว? ใน C ++ คุณได้ละเมิดกฎนิยามข้อเดียว นั่นคือพฤติกรรมที่ไม่ได้กำหนด ในภาษา C คุณได้ละเมิดกฎที่กำหนดให้การอ้างอิงทั้งหมดไปยังสัญลักษณ์เดียวต้องสอดคล้องกัน หากไม่ใช่พฤติกรรมที่ไม่ได้กำหนด พฤติกรรมที่ไม่ได้กำหนดคือ "ออกจากคุกฟรี!" การ์ดสำหรับผู้พัฒนาการนำไปใช้งาน การดำเนินการใด ๆ ที่ตอบสนองต่อพฤติกรรมที่ไม่ได้กำหนดจะเป็นไปตามมาตรฐาน การใช้งานไม่จำเป็นต้องเตือนเกี่ยวกับการตรวจจับพฤติกรรมที่ไม่ได้กำหนด

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

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


4

สำหรับ C จนถึงขณะนี้เป็นการกำหนดพฤติกรรมการใช้งาน

ตามที่ ISO / IEC9899 กล่าวว่า:

5.1.2.2.1 การเริ่มต้นโปรแกรม

1 ฟังก์ชั่นที่เรียกเมื่อเริ่มต้นโปรแกรมมีชื่อว่า main การใช้งานประกาศว่าไม่มีต้นแบบสำหรับฟังก์ชันนี้ จะต้องกำหนดด้วยประเภทผลตอบแทนของ int และไม่มีพารามิเตอร์:

int main(void) { /* ... */ }

หรือด้วยพารามิเตอร์สองตัว (เรียกในที่นี้ว่า argc และ argv แม้ว่าอาจจะใช้ชื่อใด ๆ ก็ตามเนื่องจากเป็นชื่อเฉพาะของฟังก์ชันที่มีการประกาศ):

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

หรือเทียบเท่า; หรือในลักษณะอื่น ๆ ที่กำหนดไว้สำหรับการนำไปใช้งาน


3

ไม่นี่ไม่ใช่โปรแกรมที่ถูกต้อง

สำหรับ C ++ สิ่งนี้เพิ่งสร้างขึ้นอย่างชัดเจนโดยไม่เหมาะสมโดยรายงานข้อบกพร่อง 1886: การเชื่อมโยงภาษาสำหรับ main ()ซึ่งระบุว่า:

ดูเหมือนจะไม่มีข้อ จำกัด ใด ๆ ในการให้ main () การเชื่อมโยงภาษาที่ชัดเจน แต่น่าจะมีรูปแบบที่ไม่ถูกต้องหรือได้รับการสนับสนุนตามเงื่อนไข

และส่วนหนึ่งของความละเอียดรวมถึงการเปลี่ยนแปลงต่อไปนี้:

โปรแกรมที่ประกาศตัวแปร main ในขอบเขตส่วนกลางหรือที่ประกาศชื่อ main ด้วยการเชื่อมโยงภาษา C (ในเนมสเปซใด ๆ ) มีรูปแบบไม่ถูกต้อง

เราสามารถค้นหาถ้อยคำนี้ได้ในร่างมาตรฐาน C ++ล่าสุดN4527ซึ่งเป็นแบบร่าง C ++ 1z

เวอร์ชันล่าสุดของทั้ง clang และ gcc ทำให้เกิดข้อผิดพลาด ( ดูสด ):

error: main cannot be declared as global variable
int main;
^

ก่อนรายงานข้อบกพร่องนี้เป็นพฤติกรรมที่ไม่ได้กำหนดซึ่งไม่จำเป็นต้องมีการวินิจฉัย ในทางกลับกันรหัสที่มีรูปแบบไม่ถูกต้องจำเป็นต้องมีการวินิจฉัยคอมไพลเลอร์สามารถแจ้งเตือนหรือแสดงข้อผิดพลาดได้


ขอบคุณสำหรับการอัพเดท! ดีใจที่ได้เห็นสิ่งนี้ได้รับการรวบรวมด้วยการวินิจฉัยคอมไพเลอร์ อย่างไรก็ตามฉันต้องบอกว่าฉันพบการเปลี่ยนแปลงในมาตรฐาน C ++ ที่น่างงงวย (สำหรับพื้นหลังเห็นความคิดเห็นดังกล่าวข้างต้นเกี่ยวกับชื่อของ mangling main().) ฉันเข้าใจเหตุผลในการไม่อนุญาตmain()ให้มีการเชื่อมโยงอย่างชัดเจนสเปค แต่ผมไม่เข้าใจมันอิงที่main()มีC ++ การเชื่อมโยง ของหลักสูตรมาตรฐานไม่อยู่ไม่ได้โดยตรงวิธีการจัดการการเชื่อมโยง ABI / ชื่อ mangling แต่ในทางปฏิบัติ (พูดกับ Itanium ABI) นี้จะทำให้เสียไปmain() _Z4mainvฉันขาดอะไรไป?
Geoff Nixon

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