เป็นไปได้อย่างไรที่จะประกาศว่าไม่มีอะไรอยู่ใน main () ใน C ++ และยังมีแอปพลิเคชันที่ใช้งานได้หลังจากการคอมไพล์


86

ในการให้สัมภาษณ์ฉันต้องเผชิญกับคำถามเช่นนี้:

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

อธิบายว่าสิ่งนี้เป็นไปได้อย่างไร (คำใบ้: global instance!)

ฉันอยากรู้เกี่ยวกับเรื่องนี้จริงๆว่าสิ่งนี้เป็นไปได้อย่างไร!


26
ดูคำใบ้!
R.Martinho Fernandes

14
เพราะเป็นสิ่งที่ 1) ฉันไม่เคยได้ยิน 2) เป็นเรื่องเล็กน้อยที่มีประโยชน์เพราะมีคนถามในการสัมภาษณ์ 3) การประยุกต์ใช้ภาษาที่น่าสนใจเพื่อให้รู้ 4) ฉันสามารถจดจำมันและแทงทุกคนที่เผชิญหน้าด้วย shiv เป็นสนิมถ้าฉันเห็นว่าพวกเขาใช้มันในรหัสการผลิตจริงๆ
OmnipotentEntity

4
โปรแกรมเมอร์ C ++ ที่มีความสามารถและเป็นมืออาชีพจะรู้คำตอบสำหรับคำถามนี้ หากจุดประสงค์ของคำถามสัมภาษณ์นี้คือเพื่อตรวจสอบว่าบุคคลที่ถูกสัมภาษณ์เป็นโปรแกรมเมอร์ C ++ ที่มีความสามารถและเป็นมืออาชีพคำถามก็ไม่ควรให้คำตอบแก่พวกเขา
John Dibling

1
ในการตั้งค่าการสัมภาษณ์ทางเลือกหนึ่งคือการมีตรรกะภายในฟังก์ชันใด ๆ ในโค้ดและบันทึกเอาต์พุตโดยใช้assertหรือ#pragma messageอื่น ๆ ซึ่งจะเปลี่ยนเส้นทางเอาต์พุตไปยังคอนโซลระหว่างการคอมไพล์ โปรแกรมอาจไม่ได้รวบรวมอย่างสมบูรณ์ แต่แน่นอนว่านี่เป็นวิธีที่สนุกในการแสดงความคิดแบบ "นอกกรอบ" ของคุณในระหว่างการสัมภาษณ์ สิ่งนี้ตอบสนองคำถามที่ยกมาเนื่องจากไม่ได้กล่าวถึงอะไรเกี่ยวกับไบนารีที่ถูกสร้างขึ้น แต่มันพูดถึงไฟล์ C ที่สามารถแสดง "สิ่งของ" บนคอนโซลได้ ;-)
TheCodeArtist

1
เป็นการสัมภาษณ์ของIOCCหรือไม่? :-) โอเคฉันยอมรับว่าฉันทำบ่อยครั้งสำหรับการเริ่มต้นโรงงานของฉันหรือเรียกใช้รหัสทดสอบ Btw ' ไฟล์ซอร์สโค้ดเดียว ' เป็นคำใบ้เช่นกันว่าตัวเชื่อมโยงรายการ (หลักตามค่าเริ่มต้น) จะไม่ถูกแทนที่
Valentin Heinitz

คำตอบ:


127

เป็นไปได้มากว่าจะใช้เป็น (หรือตัวแปรของมัน):

 void print_fibs() 
 {
       //implementation
 }

 int ignore = (print_fibs(), 0);

 int main() {}

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

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


3
@Nawaz มันน่าจะคุ้มค่าที่จะอ้างถึงการค้ำประกันที่แน่นอน ออบเจ็กต์ภายในหน่วยการแปลได้รับการรับประกันว่าจะเริ่มต้นตามลำดับ อ็อบเจ็กต์สตรีมมาตรฐานได้รับการรับประกันว่าจะเริ่มต้นก่อนหรือระหว่างการเริ่มต้นstd::ios_base::Initอ็อบเจ็กต์ครั้งแรก และ<iostream>รับประกันว่าจะทำงาน "ราวกับว่า" มีตัวอย่างของstd::ios_base_Initวัตถุที่ขอบเขตเนมสเปซ
James Kanze

3
@ Steve314: มันไม่กลับอะไรซึ่งเป็นเหตุผลที่ผมเคยใช้ประกอบจุลภาคเพื่อให้แน่ใจว่าประเภทของการแสดงออกทั้งเป็น(print_fibs(), 0) intนี่คือการสาธิตออนไลน์
Nawaz

1
@Nawaz ทางเลือกในการฟังก์ชั่นถือเป็นโมฆะและผู้ประกอบการจุลภาคจะกลับและตัวแปรbool bool fibsPrintedนั่นอาจจะสะอาดกว่าเล็กน้อยหากฟังก์ชั่นทำหน้าที่ที่นี่เท่านั้น (แต่ความแตกต่างคงไม่เพียงพอที่จะต้องกังวล)
James Kanze

1
+1 พูดคุยเกี่ยวกับความน่ากลัว ต้องเข้าร่วม stackoverflow เพียงเพื่อโหวตคำถามนี้และคำตอบนี้
จุดคงที่

1
@Nawaz ฉันไม่แน่ใจว่าประเด็นของคุณคืออะไร คำจำกัดความของstd::coutคือที่ไหนสักแห่งในห้องสมุด แต่ตามที่ฉันได้ชี้ให้เห็นแล้วมาตรฐานกำหนดให้ต้องเริ่มต้นก่อนที่ตัวสร้างแรกของstd::ios_base::Initวัตถุจะเสร็จสิ้นและจำเป็นต้องมีการ<iostream>ทำงานเหมือนกับว่าstd::ios_base::Initวัตถุถูกกำหนดไว้ที่ขอบเขตเนมสเปซ หากหน่วยการแปลรวมอยู่<iostream>ก่อนนิยามของอ็อบเจ็กต์ที่กำลังเริ่มต้นstd::coutจะรับประกันได้ว่าจะถูกสร้างขึ้น
James Kanze

18

หวังว่านี่จะช่วยได้

class cls
{
  public:
    cls()
    {
      // Your code for fibonacci series
    }
} objCls;

int main()
{
}

ดังนั้นทันทีที่มีการประกาศตัวแปรส่วนกลางของคลาสตัวสร้างจะถูกเรียกและคุณจะเพิ่มตรรกะเพื่อพิมพ์ชุดฟีโบนักชี


9

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


6
คุณต้องประกาศอินสแตนซ์ส่วนกลางของอ็อบเจ็กต์ซึ่ง initializer คำนวณตัวเลขฟีโบนักชี
James Kanze

4

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

ที่นี่คุณจะได้รับเช่นกับตัวเลข Fibonacci

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

หวังว่าจะช่วยคุณได้


3

สิ่งต่างๆสามารถเกิดขึ้นได้ระหว่างการเริ่มต้นของตัวแปรส่วนกลาง / คงที่ รหัสจะถูกเรียกเมื่อเริ่มต้นแอปพลิเคชัน


3

ตัวสร้าง [*] ทั้งหมดสำหรับอ็อบเจ็กต์ขอบเขตไฟล์ถูกเรียกก่อนที่จะเข้าถึงmainเช่นเดียวกับนิพจน์ initializer ทั้งหมดสำหรับตัวแปรขอบเขตไฟล์ที่ไม่ใช่อ็อบเจ็กต์

แก้ไข: นอกจากนี้ตัวทำลาย [*] ทั้งหมดสำหรับอ็อบเจ็กต์ขอบเขตไฟล์ทั้งหมดจะถูกเรียกตามลำดับการสร้างแบบย้อนกลับหลังจากmainออก ในทางทฤษฎีคุณสามารถวางโปรแกรม fibonacci ของคุณไว้ในตัวทำลายวัตถุได้

[*] โปรดทราบว่า "ทั้งหมด" จะไม่สนใจพฤติกรรมของการโหลดและการยกเลิกการโหลดไลบรารีแบบไดนามิกที่โปรแกรมของคุณไม่ได้เชื่อมโยงโดยตรง ในทางเทคนิคแล้วสิ่งเหล่านี้อยู่นอกภาษา C ++ พื้นฐาน


ทั้งหมด ? แม้แต่ผู้ที่อยู่ใน dll ที่ถูกโหลดอย่างชัดเจนหลังจากmain?
James Kanze

C ++ ไม่ได้กำหนดไลบรารีที่โหลดแบบไดนามิกในทางเทคนิคดังนั้นภายใน C ++ บริสุทธิ์คำสั่งของฉันจึงถูกต้อง ดังนั้นให้แรเงา "ทั้งหมดบันทึกสำหรับตัวเริ่มต้นและอ็อบเจ็กต์ขอบเขตไฟล์ที่มีอยู่ใน DLL / DSO ที่โหลดหลังจากถึง main" ในกรณีmainนี้ว่างเปล่าดังนั้น DLL / DSO เหล่านั้นจะต้องถูกโหลดโดยผู้ทำลายซึ่งเป็นสิ่งที่วิปริต แต่นี่เป็นวิทยาศาสตร์คอมพิวเตอร์ฉันคิดว่าเราควรระมัดระวังคำเช่น "ทั้งหมด"
Joe Z

ฉันเพิ่มข้อแม้เกี่ยวกับ 'ทั้งหมด' ในคำตอบของฉันด้านบนและยังเพิ่มหมายเหตุเกี่ยวกับ dtors
Joe Z

ใช่ แต่หวังว่าจะมา Pre C ++ 11 มีการใช้คำพังพอนบางอย่างเพื่ออนุญาต DLLs แต่ในทางปฏิบัติหมายความว่าในทางเทคนิคเท่านั้นการรับประกันไม่ได้อยู่ที่นั่นเสมอไปแม้ว่าจะอยู่ในการใช้งานจริงทั้งหมดและขึ้นอยู่กับโค้ดมากก็ตาม C ++ 11 คงที่อย่างน้อย
James Kanze
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.