ทำส่วนขยาย C เด่นใด ๆ รวมถึงประเภทจำนวนเต็มซึ่งพฤติกรรมไม่ขึ้นอยู่กับขนาดของเครื่องคำ


12

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

uint16_t ffff16 = 0xFFFF;
int64_t who_knows = ffff16 * ffff16;

ในสถาปัตยกรรมที่intมี 16 บิต (ยังคงเป็นจริงของไมโครคอนโทรลเลอร์ขนาดเล็กจำนวนมาก) รหัสนี้จะกำหนดค่า 1 โดยใช้พฤติกรรมที่กำหนดไว้อย่างดี บนเครื่องที่intมี 64 บิตก็จะกำหนดค่า 4294836225 อีกครั้งโดยใช้พฤติกรรมที่กำหนดไว้อย่างดี บนเครื่องที่intมี 32 บิตก็น่าจะกำหนดค่า -131071 (ฉันไม่ทราบว่าจะเป็นพฤติกรรมการใช้งานที่กำหนดหรือไม่ได้กำหนด) แม้ว่าโค้ดจะไม่ใช้สิ่งใดนอกจากสิ่งที่ควรจะเป็นในนาม "ประเภทขนาดคงที่" มาตรฐานจะกำหนดให้คอมไพเลอร์สองแบบที่ใช้กันในวันนี้จะให้ผลลัพธ์ที่แตกต่างกันสองแบบและคอมไพเลอร์ยอดนิยมจำนวนมากในปัจจุบัน

ตัวอย่างนี้เป็นการประดิษฐ์ที่ฉันไม่คาดหวังในรหัสโลกแห่งความจริงเพื่อกำหนดผลิตภัณฑ์ของค่า 16 บิตสองค่าโดยตรงกับค่า 64- บิต แต่มันถูกเลือกเป็นตัวอย่างสั้น ๆ เพื่อแสดงจำนวนเต็มสามวิธี การส่งเสริมการขายอาจโต้ตอบกับประเภทที่ไม่ได้ลงชื่อขนาดคงที่ มีสถานการณ์ในโลกจริงบางอย่างที่จำเป็นสำหรับการคำนวณทางคณิตศาสตร์ในประเภทที่ไม่ได้ลงนามตามกฎของเลขคณิตเลขจำนวนเต็มทางคณิตศาสตร์อื่น ๆ ที่จำเป็นที่จะต้องดำเนินการตามกฎของเลขคณิตแบบแยกส่วนและบางอย่างที่มันไม่จริง ' ไม่เป็นไร รหัสโลกแห่งความจริงมากมายสำหรับสิ่งต่าง ๆ เช่นเช็คuint32_tซัมขึ้นอยู่กับการห่อเลขคณิต mod 2³²และเมื่อสามารถทำการสุ่มได้uint16_t เลขคณิตและผลลัพธ์ที่ได้คืออย่างน้อยที่สุดถูกกำหนดว่าเป็น mod ที่ถูกต้อง 65536 (ตรงข้ามกับการเรียกพฤติกรรมที่ไม่ได้กำหนด)

แม้ว่าสถานการณ์นี้จะดูเหมือนไม่เป็นที่ต้องการอย่างชัดเจน (และจะเพิ่มมากขึ้นเมื่อการประมวลผล 64- บิตกลายเป็นบรรทัดฐานสำหรับหลาย ๆ วัตถุประสงค์), คณะกรรมการมาตรฐาน C จากสิ่งที่ฉันสังเกตเห็นชอบที่จะแนะนำคุณสมบัติภาษาที่ใช้ในการผลิตที่โดดเด่นอยู่แล้ว สภาพแวดล้อมมากกว่าการประดิษฐ์พวกเขา "ตั้งแต่เริ่มต้น" มีส่วนขยายที่โดดเด่นของภาษา C ซึ่งอนุญาตให้ใช้รหัสเพื่อระบุไม่ใช่แค่การจัดเก็บประเภท แต่ยังควรปฏิบัติในสถานการณ์ที่เกี่ยวข้องกับการส่งเสริมการขายที่เป็นไปได้หรือไม่ ฉันเห็นอย่างน้อยสามวิธีที่ส่วนขยายคอมไพเลอร์อาจแก้ไขปัญหาดังกล่าว:

  1. โดยการเพิ่มคำสั่งที่จะสั่งให้คอมไพเลอร์บังคับประเภทจำนวนเต็ม "พื้นฐาน" ให้เป็นขนาดที่แน่นอน

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

  3. โดยให้ความหมายของการประกาศประเภทที่มีลักษณะเฉพาะ (เช่นประกาศว่าเป็นชนิดที่ควรประพฤติเป็น mod-65536 ห่อแหวนพีชคณิตโดยไม่คำนึงถึงขนาดคำพื้นฐานและไม่ควรจะเป็นโดยปริยายแปลงสภาพให้แก่ประเภทอื่น ๆ เพิ่มwrap32ไปยังintควรให้ผลผลิต ผลของการพิมพ์wrap32โดยไม่คำนึงว่าintมีขนาดใหญ่กว่า 16 บิตในขณะที่การเพิ่มwrap32โดยตรงไปยัง a wrap16ควรผิดกฎหมาย (เนื่องจากไม่สามารถแปลงเป็นอื่นได้)

การตั้งค่าของฉันเองจะเป็นทางเลือกที่สามเนื่องจากมันจะช่วยให้แม้แต่เครื่องที่มีขนาดคำที่ผิดปกติสามารถทำงานกับโค้ดจำนวนมากที่คาดว่าตัวแปรจะ "ห่อ" ตามที่พวกเขาต้องการด้วยขนาดกำลังไฟของสอง; คอมไพเลอร์อาจต้องเพิ่มคำแนะนำการปิดบังบิตเพื่อให้ประเภททำงานได้อย่างเหมาะสม แต่หากรหัสต้องการประเภทที่ห่อ mod 65536 จะดีกว่าที่จะให้คอมไพเลอร์สร้างการปิดบังดังกล่าวบนเครื่องที่ต้องการมันมากกว่าจะยุ่งเหยิงซอร์สโค้ด หรือเพียงแค่มีรหัสดังกล่าวโดยใช้ไม่ได้บนเครื่องที่ต้องการการปิดบังดังกล่าว แม้ว่าฉันจะสงสัยว่ามีส่วนขยายร่วมกันใด ๆ ที่จะบรรลุพฤติกรรมแบบพกพาผ่านวิธีการข้างต้นหรือผ่านวิธีการบางอย่างที่ฉันไม่ได้คิด

เพื่อชี้แจงสิ่งที่ฉันกำลังมองหามีบางสิ่ง; สะดุดตาที่สุด:

  1. ในขณะที่มีหลายวิธีที่จะเขียนรหัสเพื่อให้แน่ใจว่าต้องการความหมาย (e กรัมกำหนดให้ปฏิบัติการทางคณิตศาสตร์ในขนาดเฉพาะ - ตัวถูกดำเนินการลงนามเพื่อให้ได้ผลลัพธ์ที่ชัดเจนหรือไม่ห่อ) หรืออย่างน้อยก็ไม่ต้องการป้องกัน ความหมาย (เช่นเงื่อนไขกำหนดประเภทwrap32_tจะเป็นuint32_tในคอมไพเลอร์ที่uint32_tจะไม่ได้รับการส่งเสริมและตัวเลขว่ามันเป็นที่ดีกว่าสำหรับรหัสซึ่งจะต้องมีwrap32_tการล้มเหลวในการสะสมในเครื่องที่ประเภทที่จะได้รับการส่งเสริมมากกว่าที่จะมีมันทำงานและผลผลิตพฤติกรรมปลอม) หากมีวิธีการเขียนรหัสใดที่จะเล่นได้ดีที่สุดกับส่วนขยายของภาษาในอนาคตการใช้สิ่งนั้นจะดีกว่าการคิดแนวทางของตัวเอง

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

ฉันไม่ได้ต้องการเห็นว่าเป็นการดูหมิ่นคณะกรรมการมาตรฐาน C หรืองานที่พวกเขาสร้างขึ้น ฉันคาดหวังว่าภายในไม่กี่ปีมันจะมีความจำเป็นในการทำให้โค้ดทำงานอย่างถูกต้องบนเครื่องที่ประเภทการส่งเสริม "ธรรมชาติ" จะมี 32 บิตเช่นเดียวกับที่มันจะเป็น 64 บิต ฉันคิดว่ามีส่วนขยายเล็กน้อยสำหรับภาษา (เล็กน้อยมากกว่าการเปลี่ยนแปลงอื่น ๆ ระหว่าง C99 nnd C14) มันเป็นไปได้ที่จะไม่เพียง แต่มอบวิธีการที่สะอาดอย่างมีประสิทธิภาพโดยใช้สถาปัตยกรรม 64 บิต แต่ในการต่อรองยังอำนวยความสะดวกในการโต้ตอบกับ เครื่องจักรที่ "ผิดปกติ - คำ - ขนาด" ซึ่งเป็นมาตรฐานในอดีตก้มลงไปข้างหลังเพื่อสนับสนุน [e กรัมทำให้เป็นไปได้สำหรับเครื่องที่มีขนาด 12 บิตcharเพื่อเรียกใช้โค้ดที่คาดว่าuint32_tเพื่อห่อ mod 2³²] ขึ้นอยู่กับทิศทางการขยายในอนาคตฉันก็คาดหวังว่ามันจะเป็นไปได้ที่จะกำหนดมาโครซึ่งจะอนุญาตให้โค้ดที่เขียนในวันนี้สามารถใช้งานได้ในคอมไพเลอร์ในวันนี้ซึ่งประเภทจำนวนเต็มเริ่มต้นจะทำหน้าที่เป็น "คาดหวัง" ประเภทจะเป็นค่าเริ่มต้นพฤติกรรมที่แตกต่างกัน แต่สามารถให้พฤติกรรมที่จำเป็น


4
@RobertHarvey คุณแน่ใจหรือไม่ ตามที่ผมเข้าใจจำนวนเต็มโปรโมชั่นถ้าintมีขนาดใหญ่กว่าuint16_t, ตัวถูกดำเนินการของคูณจะได้รับการเลื่อนตำแหน่งให้เป็นintและการคูณจะได้รับการดำเนินการเป็นintคูณและเกิดintความคุ้มค่าจะถูกแปลงสำหรับการเริ่มต้นของint64_t who_knows

3
@ RobertHarvey อย่างไร? ในรหัสของ OP ไม่มีการกล่าวถึงintแต่ก็ยังย่องเข้ามา (สมมติว่าฉันเข้าใจมาตรฐาน C ถูกต้องอีกครั้ง)

2
@ RobertHarvey แน่ใจว่ามันฟังดูแย่ แต่ถ้าคุณไม่สามารถชี้ให้เห็นได้คุณก็ไม่ได้ช่วยอะไรเลยโดยพูดว่า "nah คุณต้องทำอะไรผิด" คำถามคือทำอย่างไรจึงจะหลีกเลี่ยงการส่งเสริมการขายจำนวนเต็มหรือหลีกเลี่ยงผลกระทบของมัน!

3
@RobertHarvey: หนึ่งในเป้าหมายทางประวัติศาสตร์ของคณะกรรมการมาตรฐาน C ได้รับที่จะทำให้มันเป็นไปได้สำหรับเกือบทุกเครื่องจะมี "C คอมไพเลอร์" และมีกฎระเบียบที่มีความเฉพาะเจาะจงพอที่คอมไพเลอร์ C อิสระที่พัฒนาสำหรับเครื่องเป้าหมายด้านจะ ส่วนใหญ่จะใช้แทนกันได้ นี้ได้รับความซับซ้อนโดยความจริงที่ว่าผู้คนเริ่มคอมไพเลอร์ C เขียนเครื่องจำนวนมากก่อนที่มาตรฐานที่ถูกเกณฑ์และคณะกรรมการมาตรฐานไม่ต้องการที่จะห้ามคอมไพเลอร์จากการทำอะไรที่รหัสที่มีอยู่อาจจะพึ่งพา บางแง่มุมที่ค่อนข้างพื้นฐานของมาตรฐาน ...
SuperCat

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

คำตอบ:


4

ตามความตั้งใจทั่วไปของรหัสเช่นนี้

uint16_t ffff16 = 0xFFFF;
int64_t who_knows = ffff16 * ffff16;

คือการดำเนินการคูณใน 64 บิต (ขนาดของตัวแปรที่ได้รับผลเก็บไว้) วิธีปกติในการรับผลลัพธ์ที่ถูกต้อง (แพลตฟอร์มอิสระ) คือการร่ายหนึ่งในตัวถูกดำเนินการเพื่อบังคับใช้การคูณ 64 บิต:

uint16_t ffff16 = 0xFFFF;
int64_t i_know = (int64_t)ffff16 * ffff16;

ฉันไม่เคยพบส่วนขยาย C ใด ๆ ที่ทำให้กระบวนการนี้เป็นแบบอัตโนมัติ


1
คำถามของฉันไม่ใช่วิธีการบังคับให้มีการประเมินผลที่ถูกต้องของนิพจน์ทางคณิตศาสตร์โดยเฉพาะ (ขึ้นอยู่กับชนิดของผลลัพธ์ที่ต้องการไม่ว่าจะใช้ตัวถูกดำเนินการuint32_tหรืออื่น ๆ ใช้แมโครที่กำหนดเป็นอย่างใดอย่างหนึ่ง#define UMUL1616to16(x,y)((uint16_t)((uint16_t)(x)*(uint16_t)(y)))หรือ#define UMUL1616to16(x,y)((uint16_t)((uint32_t)(x)*(uint16_t)(y)))ขึ้นอยู่กับขนาดint) มาตรฐานที่เกิดขึ้นใหม่ใด ๆ สำหรับวิธีการจัดการสิ่งต่าง ๆ ดังกล่าวมีประโยชน์มากกว่าการกำหนดมาโครของตัวเอง
supercat

ฉันควรจะกล่าวด้วยว่าสำหรับสิ่งต่าง ๆ เช่นการคำนวณการแปลงข้อมูลและการตรวจสอบจุดประสงค์มักจะมีผลและตัดให้ขนาดตัวถูกดำเนินการ ความตั้งใจทั่วไปของการแสดงออกเช่น(ushort1*ushort2) & 65535uจะดำเนินการทางคณิตศาสตร์ mod-65536 สำหรับค่าตัวถูกดำเนินการทั้งหมด การอ่านเหตุผล C89 ฉันคิดว่ามันค่อนข้างชัดเจนว่าในขณะที่ผู้เขียนยอมรับว่ารหัสดังกล่าวอาจล้มเหลวในการใช้งานบางอย่างถ้าผลลัพธ์เกิน 2147483647 พวกเขาคาดว่าการใช้งานดังกล่าวจะกลายเป็นของหายากมากขึ้น อย่างไรก็ตามรหัสดังกล่าวบางครั้งก็ล้มเหลวใน gcc ที่ทันสมัย
supercat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.