เหตุใดขนาดของฟังก์ชันใน C จึงเป็น 1 ไบต์เสมอ


87

เมื่อเราตรวจสอบขนาดของฟังก์ชันโดยใช้sizeof()เราจะได้1 ไบต์เสมอ 1 ไบต์นี้มีความหมายว่าอย่างไร?

คำตอบ:


80

เป็นการละเมิดข้อ จำกัด และคอมไพเลอร์ของคุณควรวินิจฉัย หากคอมไพเลอร์ถึงแม้จะเป็นเช่นนั้นโปรแกรมของคุณก็มีพฤติกรรมที่ไม่ได้กำหนดไว้ [ขอบคุณ @Steve Jessop สำหรับการชี้แจงโหมดความล้มเหลวและดูคำตอบของ @Michael Burrว่าทำไมคอมไพเลอร์บางตัวจึงอนุญาต]: จาก C11, 6.5.3.4./ 1:

ห้ามใช้sizeofตัวดำเนินการกับนิพจน์ที่มีประเภทฟังก์ชัน


11
นั่นเป็นข้อ จำกัด ซึ่งหมายความว่าในคอมไพเลอร์ที่สอดคล้องกันจะได้รับการวินิจฉัย ถ้าคอมไพลเลอร์คอมไพเลอร์ต่อไป (เมื่อได้รับการวินิจฉัยแล้ว) พฤติกรรมนั้นจะไม่ถูกกำหนด หากคอมไพลเลอร์ไม่วินิจฉัย (ซึ่งเช่น gcc ไม่มี-pedantic) แสดงว่าคุณมีคอมไพลเลอร์ที่ไม่เป็นไปตามข้อกำหนดและทุกโปรแกรมมีพฤติกรรมที่ไม่ได้กำหนดไว้
Steve Jessop

1
พฤติกรรมนี้ทำให้มันอยู่ในหมวดหมู่เดียวกับส่วนขยาย GNU C แต่ฉันไม่รู้ว่าทำไมใคร ๆ ถึงต้องการพฤติกรรมนั้นดังนั้นฉันจึงไม่รู้ว่าทำไมผู้เขียน GNU จึงไม่สามารถเพิ่มมันได้
Steve Jessop

1
@SteveJessop: หมายเหตุว่านี่คือแม้จะมี-std=c11, ไม่ gnu11นี่เป็นส่วนขยายของคอมไพเลอร์ที่แปลกจริงๆ
Kerrek SB

6
โอ! ฉันพนันได้เลยว่ามันจะเปิดใช้งานเลขคณิตบนตัวชี้ฟังก์ชันแบบเดียวกับที่sizeof(void)เป็น 1 ใน GNU C.
Steve Jessop

3
เกี่ยวกับ-std=c11: ใครบางคนควรอ้างถึง-std=c*ตัวเลือกในมาตรฐานการโฆษณา พวกเขาไม่ได้เปิดใช้งานโหมดความสอดคล้องพวกเขาเป็นเพียงปิดการใช้งานส่วนขยายที่จะป้องกันไม่ให้โปรแกรมที่มีรูปแบบดีรวบรวม (เช่นเป็นtypeofคำหลักเนื่องจากโปรแกรม C ที่มีรูปแบบดีสามารถใช้เป็นชื่อตัวแปรได้ แต่gccโดยค่าเริ่มต้นจะปฏิเสธสิ่งนั้น ). ส่วนขยายปิดการใช้งานนอกจากนี้ที่อนุญาตให้โปรแกรมที่ไม่ดีเกิดขึ้นที่จะผ่าน undiagnosed คุณต้องหรือ-pedantic -pedantic-errors
Steve Jessop

56

นี่ไม่ใช่พฤติกรรมที่ไม่ได้กำหนด - มาตรฐานภาษา C ต้องการการวินิจฉัยเมื่อใช้ตัวsizeofดำเนินการกับตัวกำหนดฟังก์ชัน (ชื่อฟังก์ชัน) เนื่องจากเป็นการละเมิดข้อ จำกัด สำหรับตัวsizeofดำเนินการ

อย่างไรก็ตามในฐานะที่เป็นส่วนขยายของภาษา C, GCC ช่วยให้การทางคณิตศาสตร์ในการvoidชี้และคำแนะนำการทำงานซึ่งจะทำโดยการรักษาขนาดของที่หรือฟังก์ชั่นเป็นvoid 1เป็นผลให้ผู้sizeofประกอบการจะมีการประเมินเพื่อ1สำหรับvoidหรือฟังก์ชั่นที่มี GCC ดูhttp://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

คุณสามารถขอให้ GCC ออกคำเตือนเมื่อใช้sizeofกับตัวถูกดำเนินการเหล่านี้ได้โดยใช้-pedanticหรือ-Wpointer-arithตัวเลือกสำหรับ GCC หรือทำให้เกิดข้อผิดพลาดกับ-Werror=pointer-arith.


ตรรกะของคุณมีข้อบกพร่อง C ต้องการข้อความวินิจฉัยสำหรับบางคน แต่ไม่ใช่ทั้งหมด UB คุณไม่สามารถระบุได้ว่ามีบางอย่างกำหนดพฤติกรรมเพียงเพราะมีการวินิจฉัย
MSalters

4
C ต้องการการวินิจฉัยสำหรับการละเมิดข้อ จำกัด ทั้งหมด (5.1.1.3 การวินิจฉัยใน C99 หรือ C11) ข้อ จำกัด (3.8 ใน C99 / C11) คือ "ข้อ จำกัด ไม่ว่าจะเป็นวากยสัมพันธ์หรือความหมายซึ่งจะต้องตีความการอธิบายองค์ประกอบภาษา" ซึ่งดูเหมือนจะบอกว่าสิ่งที่ไม่เป็นไปตามข้อ จำกัด นั้นไม่สามารถตีความได้ .
Michael Burr

3
และเพื่อความชัดเจน - การละเมิดข้อ จำกัด ไม่ได้ส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนด มันเป็นข้อผิดพลาดเช่นข้อผิดพลาดทางไวยากรณ์ ตัวอย่างเช่นมาตรฐานกล่าวว่าข้อกำหนด "ถ้า" จะ "หรือ" ไม่ "ที่ปรากฏนอกข้อ จำกัดจะละเมิดพฤติกรรมนั้นจะไม่ได้กำหนดไว้" หากการละเมิดข้อ จำกัด จะส่งผลให้เกิด UB เหตุใดมาตรฐานจึงพูดถึงเฉพาะ "shalls" และ "shall nots" ที่ไม่ได้อยู่ในข้อ จำกัด ที่นี่
Michael Burr

3
ฉันไม่ได้ระบุอะไรเกี่ยวกับ UB มากนักยกเว้นว่าsizeofฟังก์ชันไม่ใช่ UB (ซึ่งฉันพูดถึงค่อนข้างมากเพราะคำตอบอื่นระบุว่าเป็น UB) แต่บางทีฉันอาจสับสนเพราะวิธีที่ฉันจัดโครงสร้างประโยค ให้ชัดเจนยิ่งขึ้น. sizeofฟังก์ชันไม่ใช่ UB (ตามที่มีการอ้างคำตอบหลายข้อ) เป็นการละเมิดข้อ จำกัด ดังนั้นจึงต้องมีการวินิจฉัย GCC อนุญาตให้เป็นส่วนขยาย
Michael Burr

2
@KerrekSB: OP ไม่ได้รับการวินิจฉัยเนื่องจากสันนิษฐานว่าใช้ GCC ซึ่งอนุญาตให้ใช้เป็นส่วนขยายภาษาซี
Michael Burr

13

หมายความว่าผู้เขียนคอมไพเลอร์ตัดสินใจที่ค่า 1 แทนที่จะทำให้ปีศาจบินออกจากจมูกของคุณ (อันที่จริงมันเป็นการใช้งานที่ไม่ได้กำหนดอีกอย่างหนึ่งsizeofที่ทำให้เรามีนิพจน์นั้น: "ตัวคอมไพเลอร์ C ต้องออกการวินิจฉัยหากเป็นสิ่งแรกที่จำเป็น การวินิจฉัยที่เป็นผลมาจากโปรแกรมของคุณจากนั้นอาจทำให้ปีศาจบินออกจากจมูกของคุณ (ซึ่งอาจเป็นข้อความวินิจฉัยที่บันทึกไว้) เช่นเดียวกับที่อาจออกการวินิจฉัยเพิ่มเติมสำหรับการละเมิดกฎไวยากรณ์หรือข้อ จำกัด เพิ่มเติม (หรือ สำหรับเรื่องนั้นไม่ว่าจะด้วยเหตุผลใดก็ตาม) " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

จากนี้มีคำแสลง "จมูกปีศาจ" สำหรับสิ่งที่คอมไพเลอร์ตัดสินใจที่จะตอบสนองต่อโครงสร้างที่ไม่ได้กำหนด 1เป็นปีศาจจมูกของคอมไพเลอร์นี้สำหรับกรณีนี้


@IlmariKaronen ฉันต้องยอมรับว่ามีเหตุผลที่คำตอบส่วนใหญ่ของฉันเกี่ยวกับ C (และ C ++) อาจเป็นไปตามหลักการไม่เชื่อเรื่องพระเจ้าโดยทั่วไปหรือนักเก็ตทางประวัติศาสตร์เช่นนั้น ประสบการณ์ C ของฉันมีพรมแดนติดกับประวัติศาสตร์ในตัวเอง :)
จอนฮันนา

7

ตามที่คนอื่น ๆ กล่าวไว้ sizeof () สามารถใช้ตัวระบุที่ถูกต้อง แต่จะไม่ส่งคืนผลลัพธ์ที่ถูกต้อง (เป็นจริงและถูกต้อง) สำหรับชื่อฟังก์ชัน นอกจากนี้อาจส่งผลให้เกิดกลุ่มอาการ "ปีศาจออกจากจมูก" อย่างแน่นอนหรือไม่ก็ได้

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

หากคุณต้องการขนาดของตัวชี้ไปยังฟังก์ชันก็จะมีขนาดเท่ากันทั้งหมดคือขนาดของคำที่อยู่บนซีพียูของคุณ


1
ประโยคที่ว่า "มันแน่นอนหรือไม่ก็ได้" ??? นั่นไม่เป็นความจริงสำหรับทุกสิ่งอย่างแท้จริงหรือ?
Kerrek SB

@KerrekSB ใช่ แต่ที่นี่อาจทำหรือไม่ทำอะไรก็ได้และยังอยู่ในกฎระเบียบ เป็นเรื่องจริงที่คอมไพเลอร์อาจปฏิเสธที่จะคอมไพล์หรือไม่int x = 1;ก็ได้ แต่มีเพียงหนึ่งในนั้นเท่านั้นที่ได้รับอนุญาตสำหรับคอมไพเลอร์ที่เป็นไปตามมาตรฐาน เมื่อsizeof()นำไปใช้กับฟังก์ชันอาจส่งคืนค่าที่ตั้งไว้หรือปฏิเสธที่จะคอมไพล์หรือส่งกลับค่าสุ่มตามสิ่งที่อยู่ในรีจิสเตอร์เฉพาะในขณะนั้น ปีศาจจมูกตามตัวอักษรไม่น่าเป็นไปได้ แต่อยู่ในตัวอักษรของมาตรฐาน
Jon Hanna

@kerrek มันอาจจะจริงเพื่ออะไรหรืออาจจะไม่เป็นเท็จสำหรับอะไรก็ได้ ... ดูที่มันคลุมเครือไร้เหตุผล
jpinto3912

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