คอมพิวเตอร์สร้างความแตกต่าง '\ 0' (ตัวอักขระ null) จาก“ unsigned int = 0” ได้อย่างไร


29

หากอยู่ในสถานการณ์ที่กำหนดคุณจะมีตัวอักษรจำนวนมาก (ลงท้ายด้วยตัวอักษรว่าง) และหลังจากนั้นในตำแหน่งถัดไปทันทีในหน่วยความจำคุณต้องการจัดเก็บ0เป็น int ที่ไม่ได้ลงนามคอมพิวเตอร์จะแยกความแตกต่างระหว่างสิ่งเหล่านี้อย่างไร สอง?


18
คุณกำลังถามเกี่ยวกับคอมพิวเตอร์ทั่วไปที่คำตอบนั้นถูกต้องสมบูรณ์ อย่างไรก็ตามเคยมีสถาปัตยกรรมบางอย่างที่ใช้หน่วยความจำที่ติดแท็กเพื่อแยกความแตกต่างระหว่างชนิดข้อมูล
grawity

12
เช่นเดียวกับที่คอมพิวเตอร์ไม่สามารถแยกความแตกต่างของโฟลต 4 ไบต์จากจำนวนเต็ม 4 ไบต์ (นำเสนอตัวเลขที่แตกต่างกันมาก)
Hagen von Eitzen

6
ในขณะที่การจบสตริงด้วย 0x00 เป็นเรื่องธรรมดามีภาษาที่ใช้สตริงที่มีความยาวนำหน้า ไบต์แรกหรือสองจะมีจำนวนไบต์ในสตริง ด้วยวิธีนี้ไม่จำเป็นต้องใช้ 0x00 ในตอนท้าย ฉันดูเหมือนจะจำ Pascal และ BASIC ทำเช่นนั้น บางทีภาษาโคบอลเช่นกัน
สว่าง

@lit ยังจัดรูปแบบส่วนหัวในโปรโตคอลการสื่อสารจำนวนมาก "สวัสดีฉันเป็นข้อความประเภทนี้และฉันมีความยาวหลายไบต์" บ่อยครั้งเนื่องจากคุณต้องเก็บชนิดข้อมูลที่ซับซ้อนไว้ภายในแล้วการเลิก null จะกลายเป็นปัญหาในการแยกวิเคราะห์
mathreadler

1
@lit: ตัวแปรส่วนใหญ่ของ Pascal และ BASIC ใช่และ PL / I และ Ada - และใน Java เนื่องจากการแชร์ซับสตริงถูกลดลงใน 7u6 อย่างมีประสิทธิภาพใช้คำนำหน้าความยาวอาร์เรย์ - แต่ COBOL เรียงลำดับเท่านั้น: คุณสามารถอ่านข้อมูลจากpic X occurs m to n depending on v( และสามารถนับได้ทุกที่ไม่เพียง แต่ก่อน) แต่การจัดเก็บนั้นซับซ้อนมากขึ้น
dave_thompson_085

คำตอบ:


86

มันไม่ได้

ตัวสิ้นสุดสตริงเป็นไบต์ที่มี 0 บิตทั้งหมด

int ที่ไม่ได้ลงชื่อคือสองหรือสี่ไบต์ (ขึ้นอยู่กับสภาพแวดล้อมของคุณ) แต่ละอันมี 0 บิตทั้งหมด

ทั้งสองรายการจะถูกเก็บไว้ในที่อยู่ที่แตกต่างกัน รหัสที่คอมไพล์แล้วของคุณทำการดำเนินการที่เหมาะสมสำหรับสตริงในตำแหน่งเดิม (ยกเว้นว่าคุณมีข้อบกพร่องในรหัสของคุณหรือรหัสที่ฉลาดอันตราย!)

แต่ไบต์เหล่านี้ทั้งหมดดูเหมือนกับ CPU ข้อมูลในหน่วยความจำ (ในสถาปัตยกรรมชุดคำสั่งที่ใช้กันทั่วไปในปัจจุบัน) ไม่มีความเกี่ยวข้องใด ๆ นั่นเป็นสิ่งที่เป็นนามธรรมที่มีอยู่ในซอร์สโค้ดและแปลว่าคอมไพเลอร์เท่านั้น

เพิ่มการแก้ไข: เป็นตัวอย่าง: มันเป็นไปได้อย่างสมบูรณ์แม้กระทั่งสามัญเพื่อดำเนินการทางคณิตศาสตร์ในไบต์ที่ทำขึ้นสตริง หากคุณมีสตริงอักขระ ASCII 8 บิตคุณสามารถแปลงตัวอักษรในสตริงระหว่างตัวพิมพ์ใหญ่และตัวพิมพ์เล็กโดยการเพิ่มหรือลบ 32 (ฐานสิบ) หรือถ้าคุณกำลังแปลไปยังรหัสตัวอักษรอื่นคุณสามารถใช้ค่าของพวกเขาเป็นดัชนีในอาร์เรย์ที่มีองค์ประกอบให้การเข้ารหัสบิตเทียบเท่าในรหัสอื่น ๆ

สำหรับซีพียูตัวอักษรนั้นเป็นจำนวนเต็มสั้นพิเศษจริงๆ (แปดบิตแต่ละอันแทน 16, 32, หรือ 64. ) สำหรับเรามนุษย์คุณค่าของมันเกิดขึ้นเพื่อเชื่อมโยงกับตัวละครที่อ่านได้ แต่ CPU ไม่มีความคิดในเรื่องนั้น นอกจากนี้ยังไม่ทราบอะไรเกี่ยวกับการประชุม "C" ของ "null by ลงท้ายสตริง" ทั้ง (และเป็นจำนวนมากได้ระบุไว้ในคำตอบและความคิดเห็นอื่น ๆ มีสภาพแวดล้อมการเขียนโปรแกรมในการประชุมที่ไม่ได้ใช้เลย) .

เพื่อให้แน่ใจว่ามีคำแนะนำบางอย่างใน x86 / x64 ที่มีแนวโน้มที่จะใช้มากกับสตริง - คำนำหน้า REP เช่น - แต่คุณสามารถใช้มันกับอาร์เรย์ของจำนวนเต็มถ้าพวกเขาได้ผลลัพธ์ที่ต้องการ


14
นั่นเป็นสาเหตุที่นักพัฒนาต้องระวังสตริง ถ้าคุณพูดว่า 100 ไบต์ต่อเนื่องคุณสามารถใส่ได้สูงสุด 99 ตัวอักษร 1 ไบต์ในนั้นบวกกับจุดสิ้นสุดในไบต์สุดท้าย หากคุณเขียนสตริง 100 ไบต์ในนั้นโปรแกรมจะไม่สามารถคิดได้ว่าสตริงนั้นจะสิ้นสุดลงที่นั่นและจะอ่านไบต์ต่อเนื่องกันจนกว่าไบต์ศูนย์บังเอิญ หากสตริงมีความยาวมากกว่า 100 ไบต์สตริงนั้นจะเขียนทับข้อมูลที่อยู่ติดกัน ภาษาโปรแกรมระดับสูง (Java, C #, JS ฯลฯ ) ดูแลสิ่งนี้ด้วยตัวเอง แต่ในภาษาระดับต่ำเช่น C, C ++, การประกอบมันเป็นความรับผิดชอบของ dev
gronostaj

18
@gronostaj ความคิดเห็นของคุณสับสนเล็กน้อย: ไม่เหมือนใน C, C ++ สตริงยังดูแลเรื่องนี้โดยอัตโนมัติ C ++ นั้นก็ไม่ได้จัดว่าเป็นภาษาระดับต่ำ (และแม้แต่ในบางครั้ง C ก็ไม่ใช่)
Konrad Rudolph

5
มีสถาปัตยกรรมซีพียู (เก่า) ที่มีเครื่องหมายประเภทบนค่าข้อมูลดังนั้นการพิจารณาจำนวนเต็มเป็นตัวชี้จะให้ข้อยกเว้น
Simon Richter

8
@JamieHanrahan โปรเซสเซอร์ IA64 มีบิตที่เรียกว่า NaT (หรือ "Not a Thing") ที่สามารถโยนข้อยกเว้นหากค่าที่ตั้งไว้
ErikF

4
@ KonradRudolph "อัตโนมัติ" ไม่ได้หมายความว่า "ไร้สาระ" แน่นอนไม่ได้อยู่ใน C ++
rackandboneman

5

ในระยะสั้นไม่มีความแตกต่าง (ยกเว้นว่า int กว้าง 2 หรือ 4 ไบต์และถ่านเพียง 1)

ประเด็นก็คือว่า libaries สมัยใหม่ทั้งหมดใช้เทคนิค null terminator หรือเก็บความยาวของสตริง และในทั้งสองกรณีโปรแกรม / คอมพิวเตอร์รู้ว่ามันมาถึงจุดสิ้นสุดของสตริงเมื่อมันอ่านอักขระว่างหรืออ่านอักขระได้มากตามขนาดที่บอก

ปัญหาเกี่ยวกับการเริ่มต้นนี้เมื่อตัวสิ้นสุด null หายไปหรือความยาวไม่ถูกต้องจากนั้นโปรแกรมเริ่มอ่านจากหน่วยความจำที่ไม่ควร


3
โอ้มีความแตกต่างในระยะสั้น - อันที่จริงสั้น ๆ เป็นที่รู้จักกันดีว่าเป็นประเภทข้อมูลที่ขึ้นอยู่กับเครื่องจักรมาก :)
rackandboneman

2

ไม่มีความแตกต่าง รหัสเครื่อง (แอสเซมเบลอร์) ไม่มีประเภทตัวแปรแทนประเภทของข้อมูลจะถูกกำหนดโดยคำสั่ง

ตัวอย่างที่ดีกว่าน่าจะเป็นintและfloatถ้าคุณมีหน่วยความจำ 4 ไบต์ไม่มีข้อมูลว่าเป็นintหรือfloat (หรืออย่างอื่น) อย่างไรก็ตามมีคำแนะนำที่แตกต่างกัน 2 คำสำหรับการเพิ่มจำนวนเต็มและการเพิ่มลอยดังนั้นหากการเพิ่มจำนวนเต็ม การเรียนการสอนจะใช้กับข้อมูลแล้วมันเป็นจำนวนเต็มและในทางกลับกัน

เช่นเดียวกับสตริงถ้าคุณมีรหัสที่พูดดูที่ที่อยู่และนับจำนวนไบต์จนกว่าจะถึง\0ไบต์คุณสามารถคิดว่ามันเป็นความยาวของสตริงการคำนวณฟังก์ชั่น

แน่นอนว่าการเขียนโปรแกรมในลักษณะนี้จะเป็นบ้าอย่างสมบูรณ์ดังนั้นนั่นเป็นสาเหตุที่เรามีภาษาระดับสูงกว่าที่คอมไพล์รหัสเครื่อง


2

คำตอบทางวิทยาศาสตร์คำเดียวคือ: เมตาดาต้า

เมตาดาต้าบอกคอมพิวเตอร์ว่าข้อมูลบางอย่างในบางตำแหน่งนั้นเป็น int สตริงสตริงรหัสโปรแกรมหรืออะไรก็ตาม ข้อมูลเมตานี้สามารถเป็นส่วนหนึ่งของรหัสโปรแกรม (ตามที่ Jamie Hanrahan พูดถึง) หรือสามารถเก็บไว้ที่ใดที่หนึ่งได้อย่างชัดเจน

CPU สมัยใหม่สามารถแยกแยะความแตกต่างระหว่างส่วนหน่วยความจำที่กำหนดให้กับรหัสโปรแกรมและส่วนข้อมูล (ตัวอย่างเช่น NX Bit https://en.wikipedia.org/wiki/NX_bit ) ฮาร์ดแวร์ที่แปลกใหม่บางตัวสามารถแยกแยะความแตกต่างระหว่างสตริงและตัวเลขได้เช่นกัน แต่ในกรณีปกติคือซอฟต์แวร์ดูแลปัญหานี้ไม่ว่าจะเป็นเมตาดาต้าโดยนัย (ในรหัส) หรือเมตาดาต้าที่ชัดเจน (VM ที่เน้นวัตถุ) มักจะเก็บเมทาดาทา (ข้อมูลประเภท / คลาส) เป็นส่วนหนึ่งของข้อมูล (วัตถุ)) .

ข้อดีของการไม่แยกความแตกต่างระหว่างข้อมูลชนิดต่าง ๆ คือการดำเนินการบางอย่างกลายเป็นเรื่องง่ายมาก ระบบย่อย I / O ไม่จำเป็นต้องทราบว่าข้อมูลที่เพิ่งอ่านจากหรือเขียนไปยังดิสก์นั้นเป็นรหัสโปรแกรมข้อความหรือตัวเลขที่มนุษย์สามารถอ่านได้ มันเป็นเพียงบิตที่ขนส่งผ่านเครื่อง ให้โค้ดโปรแกรมจัดการกับปัญหาการพิมพ์แฟนซี


0

มันไม่ได้ ที่คุณทำมัน!

หรือคอมไพเลอร์ / ล่ามของคุณ

หากคำแนะนำบอกให้คอมพิวเตอร์เพิ่ม0หมายเลขให้ทำตามนั้น ถ้าพวกเขาบอกคอมพิวเตอร์จะหยุดการพิมพ์ข้อมูลหลังจากการเข้าถึง0เป็น ' \0'ถ่านก็จะทำมัน

ภาษามีกลไกในการรับรองวิธีการปฏิบัติต่อข้อมูล ใน C ตัวแปรมีชนิดเช่นint, floatและcharและคอมไพเลอร์สร้างคำแนะนำที่เหมาะสมกับแต่ละชนิดข้อมูล แต่ C ช่วยให้คุณสามารถส่งข้อมูลจากตัวแปรหนึ่งไปยังอีกตัวแปรหนึ่งในประเภทที่แตกต่างกันแม้กระทั่งตัวชี้ที่สามารถใช้เป็นตัวเลขได้ คอมพิวเตอร์มันคือบิตทั้งหมดที่เหมือนกัน


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