Tags:

ให้ x = 10,y = 5 และ z = x*y+--y จะได้ z = 54

แต่ถ้าเขียนใหม่ เป็น z = --y+x*y จะได้ z = 44

คำถามคือ ทั้งๆที่ pre-decrement มี precedence สูงกว่า คูณ หาร แต่ทำไมอันแรกถึงไม่ทำ --y ก่อนแต่อันล่างกลับทำก่อน?

Get latest news from Blognone
By: nat3738
ContributorAndroidRed HatUbuntu
on 17 December 2009 - 22:20 #143890

เขาหมายถึงจะทำก่อนมาบวกกัน คือ

อันแรก

xy*(--y)+ (เป็น post-order)

คือ เอา x*y แล้ว ยัดเข้า stack

จากนั้นเจอ --y จึงลดค่า y ลงหนึ่ง แล้วนำค่า y ที่ลดแล้วมาใช้ในการบวก ซึ่งทำทีหลังการลดค่า

ถ้าผมเข้าใจไม่ผิดนะครับ

By: soginal
AndroidIn Love
on 17 December 2009 - 23:07 #143894
soginal's picture

+*xy--y +--y*xy

By: luckyman
ContributoriPhoneAndroidRed Hat
on 17 December 2009 - 23:49 #143901

ไม่นิยามไว้ครับ ขึ้นอยู่กับคอมไพเลอร์ (ISO C99 หัวข้อ 6.5 Expression ดู footnote 73-74)

จากผลลัพธ์ข้างบน คอมไพเลอร์ทำจากซ้ายไปขวาครับ

ตัวแรก

    1) _ <- x * y
    2) y <- y - 1
    3) z <- y + _

ตัวหลัง

    1) y <- y - 1
    2) _ <- x * y
    3) z <- y + _

ผลลัพธ์จาก gcc 4.4 ได้ตามด้านบนครับ
ส่วน visual c++ 2008 ได้ผลลัพธ์เป็น 44 ทั้งคู่

By: Peace
Contributor
on 18 December 2009 - 00:59 #143907

ขอบคุณทุกท่านมากครับ

ขอถามเพิ่มเติมว่า ถ้า compiler(gcc) ทำจากซ้ายไปขาย แล้วทำไม z = x*y+x*--y จึงได้ z = 80 หรอครับ คือ ถ้าทำจากซ้่ายมาขวา ผมเข้าใจว่า มันจะทำ x*y ก่อน ตามด้วย x*--y แล้วค่อยบวกกัน ซึ่งน่าจะได้ 50+40=90 แต่ไม่ใช่

By: luckyman
ContributoriPhoneAndroidRed Hat
on 18 December 2009 - 01:53 #143909 Reply to:143907

จริงด้วย ดูจากไฟล์ assembly กลายเป็น

    --y;
    y += y;
    z = x * y;
    movl    $10, 24(%esp)
    movl    $5, 28(%esp)
    decl    28(%esp)
    movl    28(%esp), %eax
    addl    %eax, %eax
    imull   24(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf

แถมถ้าคอมไพล์ด้วย -O2

    movl    $80, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf

สรุปคือ ไม่เข้าใจเหมือนกัน

By: soginal
AndroidIn Love
on 18 December 2009 - 09:54 #143917 Reply to:143909
soginal's picture

อย่าไปดู assembly ครับ เดี๋ยวงงเปล่าๆ จริงๆ ถ้าจขกท กำลังเรียนเรื่องวิชา compiler ก็ดูตามหลักการ prefix postfix ก็น่าจะพอแล้ว

ส่วนในกรณีนี้เกิดจากความพยายามทำ optimize ของ compiler ครับ

x*y+x*--y เปลี่ยนได้เป็น x*(y+--y) หรือ (y+--y)*x ครับ แต่มันเอา y+--y มาทำก่อน ก็เพราะว่า มันมี --y อยู่ ก็เลยดึงมาทำก่อนครับ

แต่ที่มันเอา y+--y มาทำก่อนเพราะเหตุผลว่า จะเอา z ไปคูณไม่ได้จนกว่าจะทำ y+y ก่อน แต่จะทำ y+y ไม่ได้จนกว่าจะทำ --y ดังนั้นผลลัพธ์มันก็เลยออกมาอย่างที่เห็น

By: Thaina
Windows
on 18 December 2009 - 15:58 #144012

ขอแนะนำนะครับ

ใส่วงเล็บให้เป็นนิสัยครับ สูตรคำนวน ต้องการอะไร ใส่ให้ชัดเจนไว้
มาอ่านวันหลังจะได้รู้เรื่อง
เขียนไว้โล่งๆแบบนี้ บางทีหนึ่งชี่วโมงผ่านไป อาจจะลืมไปแล้วว่าสูตรนี้จะ Flow แบบไหน

a * b - c ผมยังใส่ (a * b) - c เลย

แล้วอย่าเล่นกับ --x --y ดีกว่าครับ
Performance ที่ได้ ไม่น่าจะคุ้มกับความงงที่จะเกิดขึ้น
มันไปตีกับ Compiler อีกตะหาก

By: PiKO
ContributorAndroid
on 18 December 2009 - 21:59 #144074 Reply to:144012

จริงครับ สำหรับการ coding จริงๆ ทั้งวงเล็บและขึ้นบรรทัดใหม่
ถ้าทำได้โดยที่ทำให้ code ไม่รกและดูยาก ผมก็จะทำเสมอ

แต่นี่เข้าใจว่าต้องการศึกษาน่ะครับ (ไม่รู้จะอธิบายยังไงเหมือนกัน ^^')


:: DigiKin8 ::

By: mr_tawan
ContributoriPhoneAndroidWindows
on 22 December 2009 - 22:24 #144746 Reply to:144012
mr_tawan's picture

มันเป็นเรื่องของการศึกษาน่ะครับ :-)


  • 9tawan.net บล็อกส่วนตัวฮับ
By: ellipsis
Windows Phone
on 18 December 2009 - 17:11 #144026
ellipsis's picture

จะสอบแล้วอ่ะดิคับ

555

By: Peace
Contributor
on 18 December 2009 - 19:19 #144047

ขอบคุณทุกท่านมากครับ สรุปคือ มันขึ้นอยู่กับ compiler ว่าจะมองยังไง