บริบท
เรากำลังพอร์ตโค้ด C ที่คอมไพล์แล้วโดยใช้คอมไพเลอร์ C แบบ 8 บิตสำหรับไมโครคอนโทรลเลอร์ PIC สำนวนทั่วไปที่ใช้เพื่อป้องกันตัวแปรโกลบอลที่ไม่ได้ลงชื่อ (ตัวอย่างเช่นตัวนับข้อผิดพลาด) จากการย้อนกลับเป็นศูนย์มีดังต่อไปนี้:
if(~counter) counter++;
ผู้ประกอบการระดับบิตที่นี่กลับค่าบิตทั้งหมดและคำสั่งเป็นจริงหากcounter
น้อยกว่าค่าสูงสุด ที่สำคัญทำงานได้โดยไม่คำนึงถึงขนาดของตัวแปร
ปัญหา
ตอนนี้เรากำลังกำหนดเป้าหมายหน่วยประมวลผล ARM แบบ 32 บิตโดยใช้ GCC เราสังเกตเห็นว่ารหัสเดียวกันให้ผลลัพธ์ที่แตกต่าง เท่าที่เราสามารถบอกได้ดูเหมือนว่าการทำงานส่วนเสริม bitwise คืนค่าที่มีขนาดแตกต่างจากที่เราคาดไว้ ในการทำซ้ำสิ่งนี้เรารวบรวมใน GCC:
uint8_t i = 0;
int sz;
sz = sizeof(i);
printf("Size of variable: %d\n", sz); // Size of variable: 1
sz = sizeof(~i);
printf("Size of result: %d\n", sz); // Size of result: 4
ในบรรทัดแรกของเอาต์พุตเราได้สิ่งที่เราคาดหวัง: i
คือ 1 ไบต์ อย่างไรก็ตามส่วนประกอบ bitwise ของi
จริง ๆ แล้วสี่ไบต์ซึ่งทำให้เกิดปัญหาเนื่องจากการเปรียบเทียบกับตอนนี้จะไม่ให้ผลลัพธ์ที่คาดไว้ ตัวอย่างเช่นหากทำ (โดยที่i
การเริ่มต้นอย่างถูกต้องuint8_t
):
if(~i) i++;
เราจะเห็นi
"ล้อมรอบ" จาก 0xFF กลับเป็น 0x00 พฤติกรรมนี้แตกต่างกันใน GCC เมื่อเทียบกับเมื่อก่อนเคยทำงานตามที่เราตั้งใจไว้ในคอมไพเลอร์ก่อนหน้าและไมโครคอนโทรลเลอร์ PIC 8 บิต
เราตระหนักดีว่าเราสามารถแก้ไขปัญหานี้ได้โดยการคัดเลือกนักแสดง:
if((uint8_t)~i) i++;
หรือโดย
if(i < 0xFF) i++;
อย่างไรก็ตามในการแก้ปัญหาทั้งสองนี้ขนาดของตัวแปรจะต้องเป็นที่รู้จักและเป็นข้อผิดพลาดสำหรับผู้พัฒนาซอฟต์แวร์ การตรวจสอบขอบเขตบนเหล่านี้เกิดขึ้นทั่วทั้งฐานข้อมูล ตัวแปรมีหลายขนาด (เช่น. uint16_t
และunsigned char
อื่น ๆ ) และการเปลี่ยนแปลงเหล่านี้ใน codebase ที่ใช้งานได้ไม่ใช่สิ่งที่เรารอคอย
คำถาม
ความเข้าใจของเราเกี่ยวกับปัญหานั้นถูกต้องและมีตัวเลือกสำหรับแก้ไขปัญหาที่ไม่จำเป็นต้องเยี่ยมชมแต่ละกรณีที่เราใช้สำนวนนี้หรือไม่ สมมติฐานของเราถูกต้องหรือไม่ว่าการดำเนินการเช่นส่วนเสริม bitwise ควรส่งคืนผลลัพธ์ที่มีขนาดเท่ากับตัวถูกดำเนินการหรือไม่ ดูเหมือนว่าสิ่งนี้จะพังขึ้นอยู่กับสถาปัตยกรรมของโปรเซสเซอร์ ฉันรู้สึกว่าฉันกำลังทานยาเม็ดบ้าและ C น่าจะพกพาได้มากกว่านี้ อีกครั้งความเข้าใจของเราเกี่ยวกับเรื่องนี้อาจผิด
บนพื้นผิวนี้อาจไม่ดูเหมือนเป็นปัญหาใหญ่ แต่สำนวนที่ใช้งานมาก่อนนี้ถูกใช้ในหลาย ๆ แห่งและเรากระตือรือร้นที่จะเข้าใจสิ่งนี้ก่อนที่จะทำการเปลี่ยนแปลงที่มีราคาแพง
หมายเหตุ:มีคำถามซ้ำกันที่ดูเหมือนจะคล้ายกัน แต่ไม่ตรงกับที่นี่: การดำเนินการบิตบนถ่านให้ผลลัพธ์ 32 บิต
ฉันไม่เห็นปัญหาที่แท้จริงของปัญหาที่กล่าวถึงนั่นคือขนาดของผลลัพธ์ของส่วนประกอบ bitwise ที่แตกต่างจากสิ่งที่ส่งผ่านไปยังผู้ประกอบการ