เหตุใด“ ++ i ++” จึงไม่ถูกต้องในขณะที่ (++ i) ++ นั้นถูกต้อง?


14

ลองพิจารณารหัสต่อไปนี้:

int main() {
    int i = 2;
    int b = ++i++;
    return 3;
}

มันรวบรวมด้วยต่อไปนี้มีข้อผิดพลาด:

<source>: In function 'int main()':

<source>:3:16: error: lvalue required as increment operand

    3 |     int b = ++i++;

      |                ^~

มันฟังดูยุติธรรมสำหรับฉัน การเพิ่มขึ้นของ Postfix มีลำดับความสำคัญสูงกว่าการเพิ่มคำนำหน้าดังนั้นจึงมีการแยกวิเคราะห์รหัสint b = ++(i++);และiเป็น rvalue ดังนั้นข้อผิดพลาด

ลองพิจารณาตัวแปรนี้ด้วยวงเล็บเพื่อแทนที่ลำดับความสำคัญเริ่มต้น:

int main() {
    int i = 2;
    int b = (++i)++;
    return 3;
}

รหัสนี้รวบรวมและส่งคืน 3. ด้วยตัวเองมันฟังดูยุติธรรมสำหรับฉัน แต่มันขัดแย้งกับรหัสแรก

คำถาม: ทำไม(++i)เป็นlvalueเมื่อiไม่ได้?

ขอบคุณ!

อัปเดต:ข้อความแสดงข้อผิดพลาดที่แสดงด้านบนมาจาก gcc (x86-64 9.2) นี่คือการเรนเดอร์ที่แน่นอน: ข้อผิดพลาดกับ gcc

เสียงดังกราว x86-64 9.0.0 มีข้อความที่แตกต่างกันค่อนข้างมาก: เกิด ข้อผิดพลาดกับเสียงดังกราว

<source>:3:13: error: expression is not assignable

    int b = ++i++;

            ^ ~~~

ด้วย GCC คุณจะได้รับความประทับใจว่าปัญหาเกิดขึ้นกับตัวดำเนินการ postfix และจากนั้นคุณสามารถเดินไปรอบ ๆ ว่าทำไมจึง++iโอเคในขณะที่iไม่เป็นเช่นนั้นคำถามของฉัน ด้วย Clang มันชัดเจนว่าปัญหาเกิดขึ้นกับตัวดำเนินการส่วนหน้า


เดิมนี้ถูกติดแท็กด้วย C แน่นอนที่สุดคือไม่ถูกต้อง C.
Antti Haapala

ขออภัยจริง ๆ ! ฉันคิดว่าพฤติกรรมนั้นเหมือนกันใน C ...
23945

คำตอบ:


23

iและ++iทั้งสองเป็น lvalues ​​แต่i++เป็น rvalue

++(i++)ไม่สามารถใช้งานได้เนื่องจาก++มีการใช้ส่วนนำi++หน้าซึ่งเป็นค่า rvalue แต่(++i)++ไม่เป็นไรเพราะ++iเป็นค่า lvalue

โปรดทราบว่าใน C สถานการณ์จะแตกต่างกัน i++และ++iเป็นทั้งค่า (นี่คือตัวอย่างว่าทำไมคนควรหยุดสมมติว่า C และ C ++ มีกฎเดียวกันผู้คนใส่สมมติฐานเหล่านี้ลงในคำถามของพวกเขาซึ่งจะต้องมีการหักล้าง)


4

ประกาศนี้

int b = ++i++;

เทียบเท่ากับ

int b = ++( i++ );

ผู้ประกอบการที่เพิ่มขึ้น postfix ส่งกลับค่าของตัวถูกดำเนินการก่อนที่จะเพิ่มขึ้น

จากมาตรฐาน C ++ 17 (การเพิ่มขึ้นและลดลง 8.2.6)

1 ค่าของ postfix ++ ที่แสดงออกคือค่าของตัวถูกดำเนินการของตน ... ผลที่ได้คือ prvalue

ในขณะที่ผู้ประกอบการเพิ่ม unary ส่งกลับ lvalue หลังจากที่เพิ่มขึ้น ดังนั้นการประกาศนี้

int b = (++i)++;

ถูกต้อง ตัวอย่างเช่นคุณสามารถเขียน

int b = (++++++++i)++;

จากมาตรฐาน C ++ 17 (การเพิ่มขึ้นและลดลง 8.3.2)

1 ตัวถูกดำเนินการของคำนำหน้า ++ ถูกแก้ไขโดยการเพิ่ม 1 ตัวถูกดำเนินการจะต้องเป็นค่า lvalue ที่สามารถแก้ไขได้ ประเภทของตัวถูกดำเนินการจะต้องเป็นประเภทคณิตศาสตร์อื่นที่ไม่ใช่บูลบูลหรือตัวชี้ไปยังประเภทวัตถุที่กำหนดไว้อย่างสมบูรณ์ ผลที่ได้คือตัวถูกดำเนินการปรับปรุง; มันเป็น lvalueและเป็นบิตฟิลด์ถ้าตัวถูกดำเนินการเป็นบิตฟิลด์ ....

ให้ความสนใจว่าใน C ตัวดำเนินการทั้งสองจะคืนค่าแทนที่จะเป็น lvalue ดังนั้นใน C การประกาศนี้

int b = (++i)++;

ไม่ถูกต้อง


3

ดังนั้นรหัสจะถูกแยกวิเคราะห์เป็น int b = ++ (i ++); และฉันเป็นค่า rvalue

เลขที่iไม่ใช่ค่า rvalue iคือ lvalue i++คือ rvalue (prvalue ที่เฉพาะเจาะจง)

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