ยาว ๆ ใน c99
ในมาตรฐาน C99 long long
พวกเขาแนะนำ จุดประสงค์ของสิ่งนี้คืออะไร? จากประสบการณ์การเขียนโปรแกรม C (จำกัด ) ของฉันฉันมีเพียงทุกครั้งที่เห็น int 4 ไบต์และยาว 8 ไบต์ ตัวอย่างเช่นจาก Compiler Explorer:
ถ้าlong
เป็นแล้ว8
ทำไมต้องเพิ่มแบบอื่นlong long
? สิ่งนี้ทำอะไรกับคอมไพเลอร์ / สถาปัตยกรรม?
คำตอบ
ถ้า long เป็น 8 แล้วทำไมต้องเพิ่ม long type อีก? สิ่งนี้ทำอะไรกับคอมไพเลอร์ / สถาปัตยกรรม?
"if long is already 8" ไม่เป็นความจริงเสมอไปเนื่องจากมีโค้ดจำนวนมากที่อาศัย 32 บิตlong
และint
เป็น 32 หรือ 16 บิต
การกำหนดlong
ให้เป็น 64 บิตจะทำลายฐานรหัส นี่เป็นข้อกังวลหลัก
แต่การกำหนดlong
ให้ยังคงเป็น 32 บิต (และไม่ใช่long long
) จะไม่ทำให้สามารถเข้าถึงจำนวนเต็ม 64 บิตมาตรฐานได้ดังนั้นจึงมีเหตุผลสำหรับlong long
.
การอนุญาตlong
เป็น 32 บิตหรือ 64 บิต (หรืออื่น ๆ ) ทำให้สามารถเปลี่ยนได้
ฟังก์ชั่นต่างๆผ่านเข้า / กลับlong
เช่นfseek(), ftell()
. พวกเขาได้รับประโยชน์จากlong
การเป็นมากกว่า 32 บิตสำหรับการรองรับไฟล์ขนาดใหญ่
แนวทางปฏิบัติที่แนะนำจะส่งเสริมให้กว้างขึ้นlong
: "ประเภทที่ใช้size_t
และptrdiff_t
ไม่ควรมีอันดับการแปลงจำนวนเต็มมากกว่านั้นsigned long int
เว้นแต่ว่าการนำไปใช้นั้นรองรับออบเจ็กต์ที่มีขนาดใหญ่พอที่จะทำให้จำเป็น" สิ่งนี้เกี่ยวข้องกับขนาดหน่วยความจำที่เกิน 32 บิต
บางทีในอนาคตการใช้งานอาจใช้int/long/long long/intmax_t
เป็น 32/64/128/256 บิต
IAC ผมเห็นความกว้างคงประเภทintN_t
ความนิยมเพิ่มขึ้นมากกว่าและlong
long long
ฉันมักจะใช้การแก้ไขประเภทกว้างหรือbool
( unsigned
) char
, int
/ unsigned
, size_t
( u
) intmax_t
และลาsigned char
( unsigned
) short
( unsigned
) long
( unsigned
) long long
สำหรับกรณีพิเศษ
มาตรฐาน C รับประกันเฉพาะว่าint
สามารถ (พูดหลวม ๆ ) 2 ไบต์ a long
สามารถเป็น 4 ไบต์และlong long
สามารถเป็น 8 ไบต์
ในความเป็นจริง MSVC ยังคงใช้ 4 ไบต์long
แม้ว่าจะมี 4 ไบต์int
ก็ตาม
ข้อกำหนดเดียวที่เกี่ยวข้องสำหรับint
และlong
ตอนนี้คือint
ต้องมีอย่างน้อย 16 บิตและlong
ต้องมีอย่างน้อย 32 บิต ระบบ 16 และ 32 บิตมักจะมี 32 บิตlong
และเครื่อง 64 บิตนั้นพบได้น้อยกว่ามากในช่วงปลายทศวรรษ 1990 ดังนั้นก่อนหน้า C99 โปรแกรมเมอร์จึงไม่สามารถพึ่งพาการมีประเภทจำนวนเต็ม 64 บิตได้เลย ปัญหานั้นได้รับการแก้ไขโดยการแนะนำlong long
ซึ่งจะต้องมีอย่างน้อย 64 บิต (ฉันเชื่อว่า GCC มีให้แล้วและอาจเป็นคอมไพเลอร์อื่น ๆ เป็นส่วนเสริม)
ทุกวันนี้ระบบ 64 บิตจำนวนมาก (แต่ไม่ใช่ทั้งหมด) ใช้ 64 บิตlong
และไม่ต้องกังวลกับการทำให้long long
ใหญ่ขึ้นดังนั้นจึงเป็น 64 บิตเช่นกันและในบางแง่ก็ซ้ำซ้อน สิ่งเหล่านี้น่าจะเป็นระบบที่คุณคุ้นเคย แต่ไม่ได้แสดงถึงทุกสิ่งที่นั่น
ฉันคิดว่าคุณไม่ได้ตระหนักว่าคุณกำลังตั้งสมมติฐานผิดอย่างมากเกี่ยวกับการทำงานของข้อกำหนดความกว้างประเภท C: ISO C เพียงกำหนดช่วงค่าต่ำสุดเช่นขนาดที่เล็กที่สุดที่อนุญาตLONG_MAX
และLONG_MIN
(-2147483647 ไม่ใช่ 8 เพราะ ISO C อนุญาตให้มีส่วนเติมเต็มและจำนวนเต็ม / ขนาดที่ลงนามไม่ใช่เฉพาะส่วนเติมเต็มของ 2) การใช้งานจริงได้รับอนุญาตให้มีประเภทที่กว้างขึ้นซึ่งมักจะตรงกับความกว้างรีจิสเตอร์หรือขนาดตัวถูกดำเนินการที่เครื่องเป้าหมายทำได้อย่างมีประสิทธิภาพ
มีการเขียนเกี่ยวกับเรื่องนี้มากมายใน Stack Overflow และที่อื่น ๆ ซึ่งฉันจะไม่พยายามทำซ้ำที่นี่ ดูสิ่งนี้ด้วยhttps://en.cppreference.com/w/c/language/arithmetic_types
นั่นทำให้คุณผิดพลาดในการดูตัวเลือกประเภทความกว้างใน x86-64 System V ABI และสมมติว่าการใช้งาน C อื่น ๆ เหมือนกันฉันคิดว่า x86-64 เป็น ISA 64 บิตที่สามารถทำงานกับจำนวนเต็ม 64 บิตlong
ได้อย่างมีประสิทธิภาพดังนั้น 64 บิตจึงเป็นทางเลือกที่ดีพอสมควร
ไม่มี ABI ที่มีเหตุผลสำหรับเครื่อง 32 บิตเช่น i386 จะใช้ 64 บิตlong
เพราะไม่จำเป็นต้องใช้เพียง 32 บิต การใช้ 64 บิตหมายความว่าไม่สามารถใส่ลงในทะเบียนเดียวได้ คอมไพล์-m32
หรือคอมไพล์สำหรับ ARM 32 บิต Godbolt ยังมี GCC สำหรับ AVR และ MSP430 ในเครื่อง 8 บิตและ 16 บิต GCC จะเลือกความกว้างที่เล็กที่สุดที่ ISO C อนุญาต (2 ไบต์int
ฯลฯ )
ในปี 1999 x86-64 ไม่มีอยู่จริง (ISAs 64 บิตอื่น ๆ ทำเช่น Alpha) ดังนั้นการมองไปที่หนึ่งใน 2 ABI หลักเพื่อให้เข้าใจตัวเลือก C99 นั้นจะไม่ทำให้คุณไปไกลมากนัก
แน่นอน C ต้องการประเภทที่รับประกันว่าเป็น 64 บิตเป็นอย่างน้อยเพื่อให้ผู้ใช้เขียนโปรแกรมที่ทำคณิตศาสตร์จำนวนเต็ม 64 บิตได้อย่างมีประสิทธิภาพ
และ BTW, x86-64 สามารถทำสิ่งที่เป็นจำนวนเต็ม 32 บิตได้อย่างมีประสิทธิภาพเช่นเดียวกับ 64 บิตบางครั้งก็มีประสิทธิภาพมากกว่า ดังนั้นการสร้างlong
ประเภท 64 บิตจึงไม่ใช่เนื้อหาที่ดี รหัสบางตัวใช้long
เพราะต้องการประเภทที่ต้องเป็น 32 บิต แต่ไม่ได้รับประโยชน์จากการกำหนดให้กว้างขึ้น สำหรับรหัสดังกล่าว 64 บิตlong
จะเสียเพียงแค่การใช้แคช / แบนด์วิธหน่วยความจำและขนาดโค้ด (คำนำหน้า REX) ใน C99 ตัวเลือกที่ดีที่สุดน่าจะเป็นint_least32_t
แต่พิมพ์ได้นานและไม่ค่อยได้ใช้งานจนน่ารำคาญ
แต่ OTOH long
บางครั้งก็หวังว่าจะเป็น "ประเภทที่มีประสิทธิภาพที่กว้างที่สุด (1-register)" แม้ว่าจะไม่มีการรับประกันดังกล่าวก็ตามและ LLP64 ABI เช่น Windows x64 ที่มี 32 บิตlong
ก็ไม่เป็นเช่นนั้น
เวิร์มอีกกระป๋องหนึ่งคือ C99 int_fast32_t
และ x86-64 IMO ของ System V ทางเลือกที่ไม่ดีในการทำให้เป็นประเภท 64 บิต (ฉันมีคำตอบครึ่งข้อสำหรับCpp uint32_fast_t แก้ไขเป็น uint64_t แต่ช้ากว่าสำหรับการดำเนินการเกือบทั้งหมดกว่า uint32_t (x86_64) ทำไมถึงแก้เป็น uint64_tซึ่งฉันควรจะเสร็จ ... int_fast32_t
ทำให้เกิดคำถามว่า "เร็วเพื่ออะไร วัตถุประสงค์ "และในการนำไปใช้งานจำนวนมากไม่ใช่สิ่งที่คุณคาดหวังสำหรับหลาย ๆ กรณี
ดูสิ่งนี้ด้วย
- C ++ - ประเภทจำนวนเต็มเร็วที่สุด?
- ควรกำหนดประเภท [u] int_fastN_t สำหรับ x86_64 โดยมีหรือไม่มี x32 ABI ได้อย่างไร
- เหตุใดจึงควรเลือกใช้ uint32_t มากกว่า uint_fast32_t
- เหตุใด uint_least16_t จึงเร็วกว่า uint_fast16_t สำหรับการคูณใน x86_64
- การเพิ่มประสิทธิภาพคอมไพลเลอร์อนุญาตผ่านประเภทความกว้างที่ไม่คงที่ C / C ++ "int" "น้อยที่สุด" และ "เร็ว"
มีข้อ จำกัด บางประการ แต่ผู้เขียนคอมไพเลอร์มีอิสระที่จะเลือกความยาวสำหรับประเภทตัวแปร C มาตรฐาน (char, short, int, long, long long) โดยธรรมชาติถ่านจะเป็นไบต์สำหรับสถาปัตยกรรมนั้น (ส่วนใหญ่ที่มีคอมไพเลอร์ C คือ 8 บิต) และโดยธรรมชาติคุณไม่สามารถมีสิ่งที่เล็กกว่าใหญ่กว่าสิ่งที่ใหญ่กว่าความยาวต้องไม่เล็กกว่า int แต่อย่างแน่นอนภายในปี 1999 เราได้เห็นการเปลี่ยน x86 16 เป็น 32 บิตและตัวอย่างเช่น int เปลี่ยนจาก 16 เป็น 32 ด้วยเครื่องมือจำนวนหนึ่ง แต่อยู่นาน 32 ต่อมาการเปลี่ยน 32 ถึง 64 บิต x86 เกิดขึ้นและขึ้นอยู่กับเครื่องมือว่ามีประเภทที่พร้อมใช้ เพื่อช่วย.
ปัญหานี้เกิดขึ้นมานานแล้วและวิธีแก้ปัญหาไม่ได้เป็นการแก้ไขความยาวของประเภทซึ่งอยู่ในกฎขึ้นอยู่กับผู้เขียนคอมไพเลอร์ตามขนาด แต่ผู้เขียนคอมไพเลอร์จำเป็นต้องสร้างไฟล์ stdint.h ที่ตรงกับเครื่องมือและเป้าหมาย (stdint.h มีความเฉพาะเจาะจงสำหรับเครื่องมือและกำหนดเป้าหมายเป็นอย่างน้อยและอาจเป็นเวอร์ชันของเครื่องมือและตัวเลือกการสร้างสำหรับเครื่องมือนั้นเป็นต้น) ตัวอย่างเช่น uint32_t จะเป็น 32 บิตเสมอ ผู้เขียนบางคนจะแปลงสิ่งนั้นเป็น int อื่น ๆ เป็นเวลานาน ฯลฯ ใน stdint.h ประเภทตัวแปรภาษา C ยังคง จำกัด อยู่ที่ char, short, int และอื่น ๆ ตามภาษา (uint32_t ไม่ใช่ประเภทตัวแปรซึ่งจะถูกแปลงเป็นประเภทตัวแปรผ่าน stdint.h) วิธีแก้ปัญหา / วิธีแก้ปัญหานี้เป็นวิธีที่จะทำให้ทุกคนคลั่งไคล้และทำให้ภาษาคงอยู่
ผู้เขียนมักจะเลือกเช่นถ้า GPR เป็น 16 บิตให้ int เป็น 16 บิตและถ้า 32 บิตเป็น 32 บิตเป็นต้น แต่ก็มีอิสระบ้าง
ใช่หมายความโดยเฉพาะว่าไม่มีเหตุผลที่จะสันนิษฐานว่าเครื่องมือสองตัวสำหรับเป้าหมายเฉพาะ (เช่นคอมพิวเตอร์ที่คุณกำลังอ่านสิ่งนี้) ใช้คำจำกัดความเดียวกันสำหรับ int และ long โดยเฉพาะและหากคุณต้องการเขียนโค้ดสำหรับ แพลตฟอร์มนี้ที่สามารถพอร์ตข้ามเครื่องมือเหล่านี้ (ที่รองรับแพลตฟอร์มนี้) จากนั้นใช้ประเภท stdint.h และไม่ใช่ int, long ฯลฯ ... แน่นอนที่สุดถ้าคุณกำลังข้ามแพลตฟอร์ม msp430 mcu, arm mcu, เครื่อง arm linux ซึ่งเป็นเครื่องที่ใช้ x86 ซึ่งประเภทแม้กระทั่งสำหรับ "toolchain" เดียวกัน (เช่น gnu gcc และ binutils) ไม่มีคำจำกัดความเดียวกันสำหรับ int และ long เป็นต้นถ่านและ short มักจะเป็น 8 และ 16 บิต int และ long มีแนวโน้มที่จะแตกต่างกันมากที่สุดบางครั้งขนาดเท่ากันบางครั้งก็แตกต่างกัน แต่ประเด็นคือไม่ถือว่า
เป็นเรื่องเล็กน้อยในการตรวจจับขนาดสำหรับตัวเลือกเวอร์ชัน / เป้าหมาย / บรรทัดคำสั่งของคอมไพเลอร์หรือเพียงแค่ไปที่เส้นทาง stdint เพื่อลดปัญหาในภายหลัง