เหตุใด“ sizeof (a? true: false)” จึงให้เอาต์พุตสี่ไบต์


133

ฉันมีโค้ดเล็ก ๆ เกี่ยวกับตัวsizeofดำเนินการกับตัวดำเนินการที่เกี่ยวข้อง:

#include <stdio.h>
#include <stdbool.h>

int main()
{
    bool a = true;
    printf("%zu\n", sizeof(bool));  // Ok
    printf("%zu\n", sizeof(a));     // Ok
    printf("%zu\n", sizeof(a ? true : false)); // Why 4?
    return 0;
}

เอาท์พุท ( GCC ):

1
1
4 // Why 4?

แต่ที่นี่,

printf("%zu\n", sizeof(a ? true : false)); // Why 4?

ตัวดำเนินการ ternary ส่งคืนbooleantype และ sizeof booltype เป็น1byte ใน C

แล้วทำไมถึงsizeof(a ? true : false)ให้เอาต์พุตสี่ไบต์?


39
sizeof(true)และsizeof(false)ยังเป็น 4: ide.geeksforgeeks.org/O5jvuN
tkausl

7
คำถามที่น่าสนใจเพิ่มเติมได้ที่นี่จะเป็นสาเหตุที่การดำเนินงานนี้คือ "ไม่สอดคล้องกัน" ในการที่จะเห็นได้ชัดว่าการกำหนด_Boolให้มีขนาด 1 แต่ไม่ได้และtrue falseแต่มาตรฐานไม่ได้มีอะไรบอกเกี่ยวกับเรื่องนั้นเท่าที่ฉันสามารถบอกได้

12
@FelixPalmen เหตุผลเดียวกันว่าทำไมให้char a; sizeof(a) == 1และsizeof('a') == sizeof(int)(ใน C) ไม่เกี่ยวกับการนำไปใช้งาน แต่เกี่ยวกับภาษา
. 'สรรพนาม' ม.

10
ลองพิมพ์แล้วsizeof(true)หรือยัง? บางทีมันจะทำให้บางชัดเจนขึ้นเล็กน้อย (โดยเฉพาะอย่างยิ่งมันจะเห็นได้ชัดว่าตัวดำเนินการ ternary เป็นปลาเฮอริ่งสีแดง)
. 'สรรพนาม' ม.

4
@FelixPalmen trueมี#defined เพื่อเป็น 1 โดยstdbool.hดังนั้นใช่นี้เป็นความหมายที่แท้จริง
. 'สรรพนาม' ม.

คำตอบ:


223

#include <stdbool.h>มันเป็นเพราะคุณมี ส่วนหัวนั้นกำหนดมาโคร trueและfalseเป็น1และ0ดังนั้นคำสั่งของคุณจะมีลักษณะดังนี้:

printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4?

sizeof(int) คือ 4 บนแพลตฟอร์มของคุณ


21
"มันเป็นเพราะคุณมี #include <stdbool.h>" ไม่มันไม่ใช่ sizeof(a ? (uint8_t)1 : (uint8_t)0);นอกจากนี้ยังจะให้ผลของ 4. โปรโมชั่นจำนวนเต็มของ?:ตัวถูกดำเนินการเป็นส่วนที่สำคัญที่นี่ไม่ได้ขนาดของและtrue false
Lundin

9
@ ลุนดิน: ทั้งสองอย่างมีความสำคัญ ตามที่เขียนไว้ประเภทนี้intไม่มีการส่งเสริมการขาย สาเหตุที่คุณ "แก้ไข" ไม่ได้คือการส่งเสริมการขายเริ่มต้น
R .. GitHub STOP HELPING ICE

5
@PeterSchneider นี่ไม่ใช่ C ++ นี่คือซีใน C ++ trueและfalseมีไม่แมโคร; เป็นคำหลัก ไม่ได้กำหนดให้เป็น1และ0แต่เป็นค่าจริงและเท็จของboolประเภท
Justin

5
@PeterSchneider ไม่วันนี้คุณได้เรียนรู้บางอย่างเกี่ยวกับ C อย่าสับสนระหว่างสองภาษา ใน C ++ sizeof(true)คือ 1. การสาธิต
Rakete1111

1
จริงผสมขึ้น ไม่ได้อ่านอย่างละเอียดและพลาดโดย cppreference-link ความผิดของฉันขอบคุณ แต่ฉันมีความรู้สึกนี้เกี่ยวกับ c ++ อยู่ดี
Peter Schneider

66

ที่นี่booleanประเภทการส่งคืนตัวดำเนินการ ternary

โอเคมีอะไรมากกว่านั้น!

ใน C, ผลจากการนี้intการดำเนินงานประกอบไปด้วยเป็นประเภท [หมายเหตุด้านล่าง (1,2)]

ดังนั้นผลลัพธ์จึงเหมือนกับนิพจน์sizeof(int)บนแพลตฟอร์มของคุณ


หมายเหตุ 1: การอ้างอิงC11ตอนที่§7.18Boolean type and values <stdbool.h>

[.... ] มาโครสามตัวที่เหลือเหมาะสำหรับใช้ใน#ifคำสั่งก่อนการประมวลผล พวกเขาคือ

true

ซึ่งขยายเป็นค่าคงที่จำนวนเต็ม 1

false

ซึ่งขยายเป็นค่าคงที่จำนวนเต็ม 0, [.... ]

หมายเหตุ 2: สำหรับตัวดำเนินการตามเงื่อนไขบทที่§6.5.15 ( เน้นของฉัน )

ตัวถูกดำเนินการแรกได้รับการประเมิน มีจุดลำดับระหว่างการประเมินและการประเมินตัวถูกดำเนินการที่สองหรือสาม (แล้วแต่ว่าจะประเมินแบบใด) ตัวถูกดำเนินการที่สองจะได้รับการประเมินก็ต่อเมื่อตัวแรกเปรียบเทียบไม่เท่ากันกับ 0 ตัวถูกดำเนินการที่สามจะได้รับการประเมินก็ต่อเมื่อตัวแรกเปรียบเทียบเท่ากับ 0 ผลลัพธ์คือค่าของตัวถูกดำเนินการที่สองหรือสาม (แล้วแต่ว่าจะประเมินค่าใด), [... ]

และ

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

intด้วยเหตุนี้ผลจะเป็นชนิดจำนวนเต็มและเนื่องจากในช่วงที่ค่าคงที่ได้อย่างแม่นยำชนิด

ที่กล่าวว่าเป็นคำแนะนำทั่วไปint main()ควรจะเป็นint main (void)ไปตามมาตรฐานอย่างแท้จริง


@ user694733 อืม.. ทำไมไม่ <stdbool.h>กำหนดintMACROS เป็นประเภท.. ผิดหรือเปล่า?
Sourav Ghosh

@BasileStarynkevitch โอเคฉันเห็นว่าตอนนี้ดูเหมือนจะผิดแน่นอนอัปเดตแล้ว
Sourav Ghosh

58

ตัวดำเนินการ ternary คือปลาชนิดหนึ่งสีแดง

    printf("%zu\n", sizeof(true));

พิมพ์ 4 (หรืออะไรก็ได้ที่sizeof(int)อยู่บนแพลตฟอร์มของคุณ)

ต่อไปนี้สันนิษฐานว่าboolเป็นคำพ้องcharหรือประเภทของขนาด 1 ที่คล้ายกันและมีขนาดใหญ่กว่าintchar

เหตุผลว่าทำไมsizeof(true) != sizeof(bool)และsizeof(true) == sizeof(int)เป็นเพียงเพราะtrueเป็นไม่ได้boolการแสดงออกของประเภท intมันเป็นเรื่องการแสดงออกของประเภท มันเป็น#defineวันที่เป็นใน1stdbool.h

ไม่มี rvalues ​​ประเภทboolC เลย ทุก rvalue ดังกล่าวจะได้รับการเลื่อนตำแหน่งเป็นทันทีintแม้ว่าจะใช้เป็นข้อโต้แย้งsizeofก็ตาม แก้ไข: วรรคนี้ไม่เป็นความจริงข้อโต้แย้งที่จะไม่ได้รับการเลื่อนตำแหน่งให้sizeof intสิ่งนี้ไม่ส่งผลกระทบต่อข้อสรุปใด ๆ


คำตอบที่ดี หลังจากที่ฉันอ่านคำตอบที่ได้รับการโหวตมากที่สุดในขณะนี้ฉันคิดว่าข้อความทั้งหมดควรประเมินเป็น 4 สิ่งนี้ทำให้ทุกอย่างชัดเจนขึ้น +1
Pedro A

5
ไม่ใช่(bool)1rvalue ประเภทbool?
Ben Voigt

printf("%u\n", sizeof((char) 1));พิมพ์1บนแพลตฟอร์มของฉันในขณะที่พิมพ์printf("%u\n", sizeof(1)); 4นี่ไม่ได้หมายความว่าข้อความของคุณ "ทุก rvalue ดังกล่าวจะถูกเลื่อนระดับเป็น int ทันทีแม้ว่าจะใช้เป็นอาร์กิวเมนต์ของ sizeof" เป็นเท็จหรือไม่
JonatanE

นี่ตอบคำถามไม่ได้จริงๆ ขนาดและชนิดของtrueฯลฯ ไม่ได้เรื่องจริงๆในกรณีของ?:นับตั้งแต่ได้รับการเลื่อนตำแหน่งจำนวนเต็มintแต่อย่างใด นั่นคือคำตอบควรกล่าวถึงสาเหตุ ?:ที่ปลาชนิดหนึ่งสีแดง
Lundin

6
ฉันคิดว่าคำตอบสามารถแก้ไขปัญหาได้อย่างดีที่สุด คุณสามารถโหวตลดหรือปรับปรุงได้
. 'สรรพนาม' ม.

31

เกี่ยวกับประเภทบูลีนใน C

ประเภทบูลีนถูกนำมาใช้ในภาษาซีค่อนข้างช้าในปี 2542 ก่อนหน้านั้น C ไม่มีประเภทบูลีน แต่ใช้แทนintนิพจน์บูลีนทั้งหมด ดังนั้นตัวดำเนินการทางตรรกะทั้งหมดเช่น> == !etc จะส่งคืนintค่า1หรือ0.

เป็นเรื่องกำหนดเองสำหรับแอปพลิเคชันที่จะใช้ประเภทโฮมเมดเช่นtypedef enum { FALSE, TRUE } BOOL;ซึ่งจะลดintขนาดเป็นขนาด

C ++ มีประเภทบูลีนที่ดีกว่าและชัดเจนboolซึ่งมีขนาดไม่เกิน 1 ไบต์ ในขณะที่ประเภทบูลีนหรือนิพจน์ใน C จะลงท้ายด้วย 4 ไบต์ในกรณีที่แย่ที่สุด ความเข้ากันได้บางอย่างกับ C ++ ถูกนำมาใช้ใน C กับมาตรฐาน C99 C จากนั้นมีประเภทบูลีน_Boolและส่วนหัวstdbool.hด้วย

stdbool.hให้ความเข้ากันได้กับ C ++ ส่วนหัวนี้กำหนดมาโครbool(การสะกดแบบเดียวกับคีย์เวิร์ด C ++) ที่ขยาย_Boolเป็นประเภทซึ่งเป็นประเภทจำนวนเต็มขนาดเล็กซึ่งอาจมีขนาดใหญ่ 1 ไบต์ ในทำนองเดียวกันส่วนหัวมีสองแมโครtrueและfalseการสะกดคำเดียวกับคำหลัก C ++ แต่มีความเข้ากันได้กับโปรแกรม C เก่า ดังนั้นtrueและfalseขยายตัวออกไป1และ0ใน C intและประเภทของพวกเขาคือ มาโครเหล่านี้ไม่ได้อยู่ในประเภทบูลีนอย่างที่คีย์เวิร์ด C ++ ที่เกี่ยวข้องจะเป็น

ในทำนองเดียวกันเพื่อวัตถุประสงค์ในการใช้งานร่วมกันได้ย้อนหลังตัวดำเนินการเชิงตรรกะใน C ยังคงส่งคืนมาintจนถึงทุกวันนี้แม้ว่า C ในปัจจุบันจะมีประเภทบูลีน ในขณะที่อยู่ใน C ++ ตัวดำเนินการเชิงตรรกะจะส่งคืน a bool. ดังนั้นนิพจน์เช่นsizeof(a == b)จะให้ขนาดเป็นintC แต่มีขนาดเป็นboolC ++

เกี่ยวกับตัวดำเนินการตามเงื่อนไข ?:

ตัวดำเนินการแบบมีเงื่อนไข?:เป็นตัวดำเนินการที่แปลกและมีนิสัยแปลก ๆ มันเป็นความผิดพลาดที่จะเชื่อว่ามันเป็น 100% if() { } else {}เทียบเท่ากับ ไม่มาก

มีจุดลำดับระหว่างการประเมินตัวถูกดำเนินการที่ 1 และ 2 หรือ 3 ตัว?:ดำเนินการได้รับการรับประกันว่าจะประเมินเฉพาะตัวถูกดำเนินการที่ 2 หรือ 3 ดังนั้นจึงไม่สามารถเรียกใช้ผลข้างเคียงใด ๆ ของตัวถูกดำเนินการที่ไม่ได้รับการประเมิน รหัสเหมือนจะไม่ดำเนินการtrue? func1() : func2() func2()จนถึงตอนนี้ดีมาก

แต่มีกฎพิเศษที่ระบุว่าตัวถูกดำเนินการ 2 และ 3 ต้องได้รับโดยปริยายประเภทส่งเสริมและสมดุลกับแต่ละอื่น ๆ ที่มีการแปลงทางคณิตศาสตร์ตามปกติ ( กฎการส่งเสริมประเภทโดยนัยใน C อธิบายไว้ที่นี่ ) ที่นี้หมายถึงว่าตัวถูกดำเนินการ 2 หรือ 3 จะเสมอintเป็นอย่างน้อยที่มีขนาดใหญ่เป็น

ดังนั้นมันไม่สำคัญtrueและfalseเกิดขึ้นเป็นประเภทintC เพราะนิพจน์มักจะให้ขนาดของintเรื่องเป็นอย่างน้อย

แม้ว่าคุณจะเขียนนิพจน์ ซ้ำเป็นก็ยังคงส่งกลับขนาดของ!sizeof(a ? (bool)true : (bool)false) int

นี่เป็นเพราะการส่งเสริมประเภทโดยนัยผ่านการแปลงเลขคณิตตามปกติ


1
C ++ sizeof(bool)==1ไม่จริงรับประกัน
aschepler

1
@aschepler ไม่ แต่โลกแห่งความเป็นจริงนอกมาตรฐาน C ++ จะรับประกันได้อย่างไร ตั้งชื่อคอมไพเลอร์ที่ไม่ใช่ 1
Lundin

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

@YSC เดิมติดแท็ก C และ C ++ ทั้งคู่ดังนั้นการเปรียบเทียบระหว่างประเภทบูลที่แตกต่างกันและประวัติเบื้องหลังจึงเป็นสิ่งที่จำเป็น ฉันสงสัยว่าฉันจะเขียนส่วนแรกถ้าไม่ใช่สำหรับแท็ก C ++ อย่างไรก็ตามเราต้องเข้าใจว่าทำไม sizeof (bool) จึงเป็น 1 แต่ sizeof (false) คือ 4 ใน C
Lundin

21

คำตอบที่รวดเร็ว:

  • sizeof(a ? true : false)ประเมินเป็น4เพราะtrueและfalseถูกกำหนด<stdbool.h>เป็น1และ0ตามลำดับดังนั้นนิพจน์จึงขยายออกไปsizeof(a ? 1 : 0)ซึ่งเป็นนิพจน์จำนวนเต็มพร้อมชนิดintซึ่งใช้พื้นที่ 4 ไบต์บนแพลตฟอร์มของคุณ ด้วยเหตุผลเดียวกันsizeof(true)ก็จะประเมิน4ในระบบของคุณด้วย

อย่างไรก็ตามโปรดทราบว่า:

  • sizeof(a ? a : a)ยังประเมินเป็น4เพราะตัวดำเนินการ ternary ดำเนินการส่งเสริมการขายจำนวนเต็มบนตัวถูกดำเนินการที่สองและสามหากเป็นนิพจน์จำนวนเต็ม เช่นเดียวกับที่แน่นอนที่เกิดขึ้นsizeof(a ? true : false)และsizeof(a ? (bool)true : (bool)false)แต่หล่อแสดงออกทั้งหมดเป็นพฤติกรรมตามที่คาด:boolsizeof((bool)(a ? true : false)) -> 1

  • นอกจากนี้ยังทราบว่าดำเนินการเปรียบเทียบประเมินค่าบูลีน1หรือ0แต่มีประเภทนี้:intsizeof(a == a) -> 4

ตัวดำเนินการเดียวที่คงลักษณะบูลีนไว้aคือ:

  • ตัวดำเนินการลูกน้ำ: ทั้งคู่sizeof(a, a)และsizeof(true, a)ประเมินเป็น1เวลาคอมไพล์

  • ผู้ประกอบการที่ได้รับมอบหมาย: ทั้งสองsizeof(a = a)และมีค่าsizeof(a = true)1

  • ตัวดำเนินการที่เพิ่มขึ้น: sizeof(a++) -> 1

สุดท้ายทุกข้อข้างต้นใช้กับ C เท่านั้น: C ++ มีความหมายที่แตกต่างกันเกี่ยวกับboolประเภทค่าบูลีนtrueและfalseตัวดำเนินการเปรียบเทียบและตัวดำเนินการด้านท้าย: sizeof()นิพจน์ทั้งหมดนี้ประเมินเป็น1C ++


2
คำตอบที่ดีที่จริงพอที่จะชี้ให้เห็นว่ามันไม่ได้เรื่องจริงๆสิ่งที่ประเภทtrueและfalseเป็นเพราะ?:ถูกดำเนินการจะได้รับการเลื่อนตำแหน่งจำนวนเต็มintแต่อย่างใด จึงsizeof(a ? (uint8_t)true : (uint8_t)false)จะให้ผลเป็น 4 เช่นกัน
Lundin

คำตอบนี้ครอบคลุมประเด็นสำคัญหลักมูลค่าที่ได้รับการเลื่อนระดับเป็นint
Chinni

1

นี่คือตัวอย่างข้อมูลที่รวมอยู่ในแหล่งที่มา

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

#else /* __cplusplus */

มีมาโครtrueและfalseประกาศเป็น 1 และ 0 ตามลำดับ

อย่างไรก็ตามในกรณีนี้ประเภทคือประเภทของค่าคงที่ตามตัวอักษร ทั้ง 0 และ 1 เป็นค่าคงที่จำนวนเต็มที่พอดีกับ int ดังนั้นชนิดของมันจึงเป็น int

และsizeof(int)ในกรณีของคุณคือ 4


-3

ไม่มีประเภทข้อมูลแบบบูลใน C คือการแสดงออกทางตรรกะแทนที่จะประเมินค่าจำนวนเต็มเมื่อความจริงเป็นอย่างอื่น10

นิพจน์เงื่อนไขชอบif, for, whileหรือc ? a : bคาดหวังจำนวนเต็มถ้าตัวเลขเป็นที่ไม่ใช่ศูนย์ก็ถือว่าtrueยกเว้นกรณีพิเศษบางอย่างที่นี่เป็นฟังก์ชั่นรวม recursive ซึ่งประกอบไปด้วยผู้ประกอบการจะประเมินtrueจนกว่าจะเข้าถึงn0

int sum (int n) { return n ? n+sum(n-1) : n ;

นอกจากนี้ยังสามารถใช้เพื่อNULLตรวจสอบตัวชี้นี่คือฟังก์ชันเรียกซ้ำที่พิมพ์เนื้อหาของรายการที่เชื่อมโยงเดี่ยว

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.