ระวังถูก compiler หลอก (2) ครั้งแรกที่ผมรู้จักภาษา C มีคนบอกผมว่า C เป็นภาษาที่เวลาเขียนจะเกิดข้อผิดพลาดได้ง่ายและหาที่ผิดได้ยากมาก ผมฟังแล้วแอบแย้งในใจว่า ภาษาไหนมันก็ผิดได้ทั้งนั้นถ้าคนเขียนมันเขียนผิด ![]() ต่อมาพอผมเริ่มเขียนภาษา C ก็เห็นว่ามีเรื่องยากอยู่ไม่กี่เรื่องที่อาจทำให้เกิดข้อผิดพลาดได้ เช่นเรื่องของการทำ indent ไม่ถูกที่ ทำให้งงกับ logic ของ if-else หรือเรื่อง pointer ที่เวลาเขียนผิดแล้วอาจทำให้โปรแกรมตายได้ มันก็เป็นเรื่องปรกติ ก็คนเขียนมันเขียนผิดนี่ ![]() จนอีกหลายปีถัดมาผมได้มีโอกาสไปเขียนภาษา C บนเครื่อง server แล้วพบว่าภาษา C ที่ผมเคยเขียนได้ กลับ compile ไม่ผ่าน หรือรันแล้วเพี้ยนๆ หรือมี error ![]() ผมเลยกลับมาอ่าน textbook ภาษา C ใหม่ คราวนี้อ่านอย่างละเอียด ที่ผ่านมาถึงแม้ว่าผมเขียนโปรแกรมภาษา C มาหลายปี มีโปรแกรมที่ทำงานได้ออกมามากมาย แต่ผมก็ไม่ได้เข้าใจภาษา C จริงๆ การอ่าน textbook ทำให้ผมเข้าใจดีขึ้น และเห็นว่า ภาษา C เกิดข้อผิดพลาดได้ง่ายจริงๆ ตอนที่ผมเริ่มหัดเขียนภาษา C ผมก็เริ่มแบบที่คนทั่วๆไปทำกัน คือหาหนังสือมาเล่มนึงกับ compiler ตัวนึง แล้วก็เริ่มหัดเขียน พอเริ่มเขียนได้บ้างก็เลิกอ่านหนังสือ แล้วใช้ compiler เป็นครูแทน สงสัยอะไรก็เขียนโปรแกรมทดสอบ แล้ว compile และรันดูว่าใช้ได้หรือเปล่า ผลก็คือผมเขียนภาษา C ที่ถูกต้องตาม compiler กับ platform ที่ผมใช้ ไม่ใช่เขียนภาษา C ที่ถูกต้องตาม standard ของภาษา เรียกได้ว่าถูก compiler หลอกเอาครับ พอเปลี่ยน compiler หรือ platform ก็เลยเกิดปัญหามากมาย ผมเข้าใจว่านี่เป็นปัญหาที่เกิดขึ้นกับคนส่วนใหญ่ด้วย โดยเฉพาะเดี๋ยวนี้ compiler หลายตัว เป็น C/C++ คือใช้ได้ทั้งภาษา C กับ C++ เลยไม่รู้ว่าเป็นภาษาไหนกันแน่ ลองอ่านที่ผมเขียนเล่าไว้ใน entry ที่แล้วดู ข้อผิดพลาดที่พบได้บ่อยของภาษา C มีต้นเหตุมาจาก 3 เรื่องหลักๆ คือ - implementation-defined - undefined - syntax rule implementation-defined หมายความว่า ให้เป็นเรื่องของ compiler แต่ละตัวไปทำเอง ใน standard ไม่ได้กำหนดว่าต้องทำยังไง ซึ่ง compiler แต่ละตัวต้องกำหนด (define) ให้ชัดเจนไปเลยว่าจะทำ (implement) ยังไง ตัวอย่างของ implementation-defined ที่พบบ่อยคือ data type ที่เป็น char ใน standard ไม่ได้กำหนดว่า char จะเป็น signed char หรือ unsigned char ให้ compiler แต่ละตัวไปกำหนดเอาเอง ส่วน undefined หมายความว่า ใน standard ไม่ได้กำหนดว่าจะทำยังไง หรือเกิดอะไรขึ้น compiler ก็ไม่จำเป็นต้องกำหนดว่าจะทำยังไง หรือเกิดอะไรขึ้น สรุปว่ามีอิสระกันได้เต็มที่ ตัวอย่างของ undefined คือ ค่าเริ่มต้นของ automatic variable ซึ่งจะเป็นค่าอะไรก็ได้ สองข้อนี้แหละครับที่ทำให้เขียนโปรแกรมถูก แต่ไป compile และรันในแต่ละ compiler แล้วอาจได้ผลลัพธ์ไม่เหมือนกัน ส่วน syntax rule ก็เป็นปัญหาที่เกิดจาก syntax ของภาษา C เอง ที่ออกแบบมาให้ยืดหยุ่นมาก แต่เปิดช่องให้ทำผิดได้ง่ายๆ คราวนี้พอแค่นี้ก่อนนะครับ โอกาสหน้าจะเอาตัวอย่างข้อผิดพลาดที่เกิดขึ้นในแต่ละเรื่องมาให้ดูครับ ![]() |