題 計算機如何將“\ 0”(空字符)與“unsigned int = 0”區分開來?


如果在給定的情況下,你有一個字符數組(當然用空字符結束),就在那之後,在內存中的下一個位置,你想要存儲 0 作為unsigned int,計算機如何區分這兩者?


29
2017-10-01 10:15


起源


你問的是答案完全正確的典型計算機。但是,曾經有過 一些 使用的架構 標記的內存 區分數據類型。 - grawity
計算機無法將4字節浮點數與4字節整數區分開來(表示一個非常不同的數字)。 - Hagen von Eitzen
雖然以0x00結尾的字符串很常見,但有些語言使用長度為前綴的字符串。第一個或第一個字節將包含字符串中的字節數。這樣,不需要最後的0x00。我似乎記得Pascal和BASIC這樣做。也許COBOL也是如此。 - lit
@lit也是許多通信協議中的頭格式。 “你好,我是這種消息,而且這個字節很長”。通常因為你需要在裡面存儲複雜的數據類型,然後null終止變得麻煩解析。 - mathreadler
@lit:Pascal和BASIC的大多數變體是,PL / I和Ada - 並且在Java中因為子串共享在7u6中被刪除,所以有效地使用了數組長度前綴 - 但COBOL只排序:你可以 讀 來自的數據 pic X occurs m to n depending on v (並且計數可以在任何地方,而不僅僅是之前),但是 存儲 它更複雜。 - dave_thompson_085


答案:


它沒有。

字符串終結符是一個包含全0位的字節。

unsigned int是兩個或四個字節(取決於您的環境),每個字節包含所有0位。

這兩個項目存儲在不同的地址。已編譯的代碼執行適用於前一個位置的字符串的操作,以及適用於後者的無符號二進制數的操作。 (除非您的代碼中有錯誤,或者某些危險的聰明代碼!)

但所有這些字節看起來與CPU相同。存儲器中的數據(在大多數當前常見的指令集體系結構中)沒有與之相關的任何類型。這是一種僅存在於源代碼中的抽象,僅對編譯器有意義。

編輯添加:作為一個例子:對構成字符串的字節執行算術是完全可能的,甚至是常見的。如果您有一個8位ASCII字符串,您可以通過加上或減去32(十進制)來轉換大小寫字母之間的字母。或者,如果要轉換為另一個字符代碼,則可以將它們的值用作數組的索引,該數組的元素在其他代碼中提供等效的位編碼。

對於CPU來說,字符實際上是超短整數。 (每個八位而不是16位,32位或64位。)對於我們人類來說,它們的值恰好與可讀字符相關聯,但CPU並不知道這一點。它也不知道任何關於“空字節結束字符串”的“C”約定(並且正如許多人在其他答案和註釋中所指出的那樣,存在根本不使用該約定的編程環境) 。

可以肯定的是,x86 / x64中有一些指令往往會大量使用字符串 - 例如REP前綴 - 但是如果它們達到了預期的結果,你也可以在整數數組中使用它們。


86
2017-10-01 10:22



這就是開發人員必須小心使用字符串的原因。如果你有100個連續字節,那麼你最多可以容納99個1字節字符加上最後一個字節中的終結符。如果你在那裡寫一個100字節的字符串,程序將無法弄清楚字符串在那裡結束並繼續讀取連續的字節,直到巧合的零字節。如果字符串長度超過100個字節,它將覆蓋一些相鄰數據。高級編程語言(Java,C#,JS等)自己處理這個問題,但是在C,C ++這樣的低級語言中,彙編它的開發人員的響應能力。 - gronostaj
@gronostaj你的評論有點混亂:與C不同,C ++字符串也會自動處理。 C ++通常也不被歸類為低級語言(有時甚至不是C語言)。 - Konrad Rudolph
有(舊)CPU架構在數據值上有類型標記,因此取消引用整數作為指針將產生異常。 - Simon Richter
@JamieHanrahan IA64處理器 有一點叫做NaT (或“Not a Thing”)如果設置了值,則可以拋出異常。 - ErikF
@KonradRudolph“自動”並不意味著“萬無一失”,當然不是在C ++中 - rackandboneman


簡而言之,沒有區別(除了int寬2或4字節,char只有1)。

問題是所有現代庫都使用空終止技術或存儲字符串的長度。在這兩種情況下,當程序/計算機讀取空字符或讀取了大小告訴它的字符數時,程序/計算機知道它到達字符串的末尾。

當null終止符丟失或長度錯誤時,這啟動的問題,因為程序開始從內存中讀取它不應該。


5
2017-10-01 10:27



哦,簡而言之 - 實際上,short是一種因機器相關數據類型而臭名昭著的:) - rackandboneman


沒有區別。機器代碼(彙編器)沒有變量類型,而是由指令確定數據的類型。

一個更好的例子是 int 和 float,如果內存中有4個字節,則不知道它是否為a int或者a float (或完全不同的東西),但是有兩個不同的整數加法和浮點加法指令,所以如果對數據使用整數加法指令,則它是整數,反之亦然。

與字符串相同,如果您有代碼,例如,查看地址併計算字節直到達到a \0 byte,您可以將其視為函數計算字符串的長度。

當然這樣的編程將是完全瘋狂的,所以這就是為什麼我們有更高級別的語言編譯成機器代碼和幾乎沒有直接彙編程序。


2
2017-10-02 10:22





科學單詞答案將是:元數據。

元數據告訴計算機某個位置的某些數據是int,字符串,程序代碼還是其他什麼。此元數據可以是程序代碼的一部分(如 Jamie Hanrahan提到)或者它可以明確存儲在某個地方。

現代CPU通常可以區分分配給程序代碼的存儲區域和數據區域(例如,NX位 https://en.wikipedia.org/wiki/NX_bit)。一些奇特的硬件也可以區分字符串和數字,是的。但通常的情況是,軟件會處理此問題,或者通過隱式元數據(在代碼中)或顯式元數據(面向對象的VM通常將元數據(類型/類信息)存儲為數據(對象)的一部分) 。

不區分不同類型數據的優點是某些操作變得非常簡單。 I / O子系統不一定需要知道它剛從磁盤讀取或寫入磁盤的數據實際上是程序代碼,人類可讀文本還是數字。它只是通過機器傳輸的所有東西。讓程序代碼處理花哨的輸入問題。


2
2017-10-03 12:07





它沒有。你來弄吧!

或者你的編譯器/解釋器。

如果說明告訴計算機添加 0 作為一個數字,它會做到這一點。如果他們告訴計算機到達後停止打印數據 0, 作為一個 '\0' char,它會做的。

語言具有確保如何處理數據的機制。在C變量中有類型,如 intfloat 和 char,編譯器為每種數據類型生成正確的指令。但是C允許您將數據從變量轉換為另一個不同類型的變量,甚至指針也可以用作數字。計算機它就像其他任何東西一樣。


0
2017-10-03 21:49





空字符是一個字節,unsigned int是兩個字節。


0
2017-10-04 07:35