อ่าน 3 นาที
สตริงที่สิ้นสุดด้วยค่าว่าง
ในการเขียนโปรแกรมคอมพิวเตอร์สตริงที่ลงท้ายด้วยค่าว่าง (null-terminated string)คือสตริงอักขระที่จัดเก็บเป็นอาร์เรย์ที่มีอักขระและลงท้ายด้วยอักขระว่าง (อักขระที่มีค่าภายในเป็นศูนย์..
สตริงที่สิ้นสุดด้วยค่าว่าง
ในการเขียนโปรแกรมคอมพิวเตอร์สตริงที่ลงท้ายด้วยค่าว่าง (null-terminated string)คือสตริงอักขระที่จัดเก็บเป็นอาร์เรย์ที่มีอักขระและลงท้ายด้วยอักขระว่าง (อักขระที่มีค่าภายในเป็นศูนย์ เรียกว่า "NUL" ในบทความนี้ ไม่เหมือนกับสัญลักษณ์เลขศูนย์) ชื่อเรียกอื่น ๆ ได้แก่สตริง Cซึ่งหมายถึงภาษาการเขียนโปรแกรม CและASCIIZ [ 1 ] (แม้ว่า C จะสามารถใช้การเข้ารหัสอื่นนอกเหนือจากASCII ได้ ก็ตาม)
การหาความยาวของสตริงทำได้โดยการค้นหาอักขระ NUL ตัวแรก ซึ่งอาจใช้เวลานานเนื่องจากใช้เวลา O( n ) ( เวลาเชิงเส้น ) เมื่อเทียบกับความยาวของสตริง นอกจากนี้ยังหมายความว่าสตริงต้องไม่มีอักขระ NUL (มีอักขระ NUL อยู่ในหน่วยความจำ แต่จะอยู่หลังอักขระตัวสุดท้าย ไม่ได้อยู่ในสตริง)
ประวัติศาสตร์
สตริงที่ลงท้ายด้วยค่าว่างถูกสร้างขึ้นโดย.ASCIZคำสั่งของภาษาแอสเซมบลีPDP-11 และคำสั่งของ ภาษาแอสเซมบลีมาโคร MACRO-10สำหรับPDP-10ซึ่งมีมาก่อนการพัฒนาภาษาโปรแกรม C แต่ก็มีการใช้สตริงรูปแบบอื่น ๆ บ่อยครั้ง ASCIZ
ในขณะที่ภาษา C (และภาษาที่พัฒนามาจาก C) ถูกพัฒนาขึ้น หน่วยความจำมีจำกัดอย่างมาก ดังนั้นการใช้หน่วยความจำส่วนเกินเพียงหนึ่งไบต์เพื่อเก็บความยาวของสตริงจึงเป็นสิ่งที่น่าสนใจ ทางเลือกที่เป็นที่นิยมในขณะนั้น ซึ่งมักเรียกว่า "สตริงแบบปาสคาล" (คำที่ทันสมัยกว่าคือ "สตริงที่มีคำนำหน้าความยาว ") ใช้ไบต์ นำหน้า เพื่อเก็บความยาวของสตริง วิธีนี้ทำให้สตริงสามารถมี NUL ได้ และทำให้การค้นหาความยาวต้องใช้การเข้าถึงหน่วยความจำเพียงครั้งเดียว ( เวลา O(1) (คงที่) ) แต่จำกัดความยาวของสตริงไว้ที่ 255 ตัวอักษรเดนนิส ริตชี นักออกแบบภาษา C เลือกที่จะปฏิบัติตามธรรมเนียมการสิ้นสุดด้วยค่า null เพื่อหลีกเลี่ยงข้อจำกัดเกี่ยวกับความยาวของสตริง และเนื่องจากการรักษาจำนวนดูเหมือนจะไม่สะดวกเท่ากับการใช้ตัวจบสตริงในประสบการณ์ของเขา[ 2 ]
สิ่งนี้มีอิทธิพลต่อ การออกแบบ ชุดคำสั่ง CPU บ้าง CPU บางตัวในช่วงทศวรรษ 1970 และ 1980 เช่นZilog Z80และDEC VAXมีคำสั่งเฉพาะสำหรับการจัดการสตริงที่มีคำนำหน้าความยาว อย่างไรก็ตาม เมื่อสตริงที่ลงท้ายด้วยค่าว่างได้รับความนิยมมากขึ้น นักออกแบบ CPU ก็เริ่มคำนึงถึงเรื่องนี้ ดังเช่นที่เห็นได้จากการตัดสินใจของ IBM ที่จะเพิ่มคำสั่ง "Logical String Assist" ลงในES/9000 520 ในปี 1992 และคำสั่งสตริงเวกเตอร์ลงในIBM z13ในปี 2015 [ 3 ]
Poul-Henning KampนักพัฒนาFreeBSDเขียนในACM Queueโดยอ้างถึงชัยชนะของสตริงที่ลงท้ายด้วยค่าว่างเหนือความยาว 2 ไบต์ (ไม่ใช่ 1 ไบต์) ว่าเป็น "ความผิดพลาด 1 ไบต์ที่แพงที่สุด" เท่าที่เคยมีมา[ 4 ]
ข้อจำกัด
แม้ว่าการนำไปใช้จะทำได้ง่าย แต่รูปแบบการแสดงผลนี้มีแนวโน้มที่จะเกิดข้อผิดพลาดและปัญหาด้านประสิทธิภาพ
การสิ้นสุดด้วยค่าว่าง (Null-termination ) ก่อให้เกิดปัญหาด้านความปลอดภัย มาโดยตลอด [ 5 ]การแทรกค่า NUL เข้าไปตรงกลางสตริงจะทำให้สตริงถูกตัดทอนโดยไม่คาดคิด[ 6 ]ข้อผิดพลาดที่พบบ่อยคือการไม่จัดสรรพื้นที่เพิ่มเติมสำหรับค่า NUL ทำให้ค่า NUL ถูกเขียนทับหน่วยความจำที่อยู่ติดกัน อีกข้อผิดพลาดหนึ่งคือการไม่เขียนค่า NUL เลย ซึ่งมักจะไม่ถูกตรวจพบระหว่างการทดสอบเนื่องจากบล็อกหน่วยความจำนั้นมีค่าเป็นศูนย์อยู่แล้ว เนื่องจากค่าใช้จ่ายในการหาความยาว โปรแกรมหลายโปรแกรมจึงไม่ใส่ใจก่อนที่จะคัดลอกสตริงไปยังบัฟเฟอร์ ขนาดคงที่ ทำให้เกิดบัฟเฟอร์โอเวอร์โฟลว์หากสตริงนั้นยาวเกินไป
เนื่องจากไม่สามารถจัดเก็บค่าศูนย์ได้ จึงจำเป็นต้องแยกข้อมูลข้อความและข้อมูลไบนารีออกจากกัน และจัดการด้วยฟังก์ชันที่แตกต่างกัน (โดยข้อมูลไบนารีจำเป็นต้องระบุความยาวของข้อมูลด้วย) ซึ่งอาจนำไปสู่ความซ้ำซ้อนของโค้ดและข้อผิดพลาดหากใช้ฟังก์ชันที่ไม่ถูกต้อง
ปัญหาเรื่องความเร็วในการหาความยาวมักจะสามารถแก้ไขได้โดยการรวมเข้ากับการดำเนินการอื่นที่ใช้เวลา O( n ) อยู่แล้ว เช่นในกรณีของstrlcpyอย่างไรก็ตาม วิธีนี้ไม่ได้ทำให้ได้API ที่ใช้ งาน ง่ายเสมอไป
การเข้ารหัสอักขระ
สตริงที่ลงท้ายด้วยค่าว่าง (null-terminated strings) กำหนดให้การเข้ารหัสไม่ใช้ไบต์ศูนย์ (0x00) ที่ใดเลย ดังนั้นจึงไม่สามารถจัดเก็บสตริงASCIIหรือUTF-8 ที่เป็นไปได้ทั้งหมดได้ [ 7 ] [ 8 ] [ 9 ]อย่างไรก็ตาม เป็นเรื่องปกติที่จะจัดเก็บชุดย่อยของ ASCII หรือ UTF-8 – ทุกอักขระยกเว้น NUL – ในสตริงที่ลงท้ายด้วยค่าว่าง ระบบบางระบบใช้ " UTF-8 ที่แก้ไขแล้ว " (modified UTF-8) ซึ่งเข้ารหัส NUL เป็นไบต์ที่ไม่ใช่ศูนย์สองไบต์ (0xC0, 0x80) และทำให้สามารถจัดเก็บสตริงที่เป็นไปได้ทั้งหมดได้ แต่มาตรฐาน UTF-8 ไม่อนุญาตให้ทำเช่นนี้ เนื่องจากเป็นการเข้ารหัสที่ยาวเกินไปและถือเป็นความเสี่ยงด้านความปลอดภัย อาจใช้ไบต์อื่นเป็นจุดสิ้นสุดของสตริงแทน เช่น 0xFE หรือ 0xFF ซึ่งไม่ได้ใช้ใน UTF-8
UTF-16ใช้จำนวนเต็ม 2 ไบต์ และเนื่องจากไบต์ใดไบต์หนึ่งอาจเป็นศูนย์ได้ (และในความเป็นจริง ไบต์ เว้นไบต์จะเป็นศูนย์เมื่อแสดงข้อความ ASCII) จึงไม่สามารถจัดเก็บในสตริงไบต์ที่ลงท้ายด้วยค่าว่างได้ อย่างไรก็ตาม บางภาษาใช้สตริงของ อักขระ UTF-16 ขนาด 16 บิต ซึ่งลงท้ายด้วยค่าว่าง 16 บิต (0x0000)
การปรับปรุง
มีการพยายามหลายครั้งเพื่อลดข้อผิดพลาดในการจัดการสตริงในภาษา C กลยุทธ์หนึ่งคือการเพิ่มฟังก์ชันที่ปลอดภัยกว่า เช่น `insert` strdupและ ` strlcpyinsert` ในขณะที่ยกเลิกการใช้งานฟังก์ชันที่ไม่ปลอดภัยเช่น gets`insert` อีกกลยุทธ์หนึ่งคือการเพิ่มตัวห่อแบบเชิงวัตถุรอบสตริงในภาษา C เพื่อให้สามารถเรียกใช้ได้เฉพาะฟังก์ชันที่ปลอดภัยเท่านั้น อย่างไรก็ตาม ยังสามารถเรียกใช้ฟังก์ชันที่ไม่ปลอดภัยได้อยู่ดี
ไลบรารีสมัยใหม่ส่วนใหญ่แทนที่สตริง C ด้วยโครงสร้างที่มีค่าความยาว 32 บิตขึ้นไป (มากกว่าที่เคยใช้สำหรับสตริงที่มีคำนำหน้าความยาวมาก) และมักจะเพิ่มตัวชี้อีกตัว จำนวนการอ้างอิง และแม้แต่ค่า NUL เพื่อเพิ่มความเร็วในการแปลงกลับเป็นสตริง C หน่วยความจำในปัจจุบันมีขนาดใหญ่กว่ามาก ดังนั้นหากการเพิ่ม 3 (หรือ 16 หรือมากกว่า) ไบต์ให้กับแต่ละสตริงเป็นปัญหาจริง ๆ ซอฟต์แวร์จะต้องจัดการกับสตริงขนาดเล็กจำนวนมากจนวิธีการจัดเก็บอื่น ๆ จะช่วยประหยัดหน่วยความจำได้มากกว่า (ตัวอย่างเช่น อาจมีข้อมูลซ้ำกันมากจนตารางแฮชจะใช้หน่วยความจำน้อยกว่า) ตัวอย่างเช่นไลบรารีเทมเพลตมาตรฐานC++ , Qt , MFCและการใช้งานแบบ C จากCore Foundationรวมถึงเวอร์ชันObjective-CจากFoundation ของ Apple โครงสร้างที่ซับซ้อนกว่าอาจถูกนำมาใช้เพื่อจัด เก็บ สตริง เช่นropestd::stringQStringCStringCFStringNSString
ดูเพิ่มเติม
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ สตริงที่สิ้นสุดด้วยค่าว่าง
ในการเขียนโปรแกรมคอมพิวเตอร์สตริงที่ลงท้ายด้วยค่าว่าง (null-terminated string)คือสตริงอักขระที่จัดเก็บเป็นอาร์เรย์ที่มีอักขระและลงท้ายด้วยอักขระว่าง (อักขระที่มีค่าภายในเป็นศูนย์..
ประวัติศาสตร์
สตริงที่ลงท้ายด้วยค่าว่างถูกสร้างขึ้นโดย .ASCIZ คำสั่งของ ภาษาแอสเซมบลี PDP-11 และคำสั่งของ ภาษาแอสเซมบลีมาโคร MACRO-10 สำหรับ PDP-10 ซึ่งมีมาก่อนการพัฒนาภาษาโปรแกรม C แต่ก็มีการใช้สตริงรูปแบบอื่น ๆ บ่อยครั้ง ASCIZ
ข้อจำกัด
แม้ว่าการนำไปใช้จะทำได้ง่าย แต่รูปแบบการแสดงผลนี้มีแนวโน้มที่จะเกิดข้อผิดพลาดและปัญหาด้านประสิทธิภาพ
การเข้ารหัสอักขระ
สตริงที่ลงท้ายด้วยค่าว่าง (null-terminated strings) กำหนดให้การเข้ารหัสไม่ใช้ไบต์ศูนย์ (0x00) ที่ใดเลย ดังนั้นจึงไม่สามารถจัดเก็บสตริง ASCII หรือ UTF-8 ที่เป็นไปได้ทั้งหมดได้ [ 7 ] [ 8 ] [ 9 ] อย่างไรก็ตาม เป็นเรื่องปกติที่จะจัดเก็บชุดย่อยของ ASCII หรือ UTF-8...