標籤:

外國人編程出錯也會出現「燙燙燙燙」嗎?為什麼會出現這個?


調試模式下VS會給棧內存加上額外的保護段並且用0xCC填充,0xCC在x86下是INT 3指令,這個指令會觸發斷點,這樣調試器就可以發現程序因為越界覆蓋了返回地址之類的各種各樣的原因執行到了堆棧數據裡面……

堆當中則會用0xCD來填充,也就是「屯屯屯屯屯」

屯和燙都是GBK編碼的結果,所以只有簡體中文Windows,而且程序鏈接了ANSI版本的API才會顯示這個。現代的程序可以選擇使用UTF-16的Unicode版本的庫,這種情況下會變成韓文????。

如果是台灣(BIG-5)則會顯示「昍昍昍」,日本(Shift-JIS)應該會顯示「??????」

從Google搜索的結果來看,這幾個字也是廣為世界人民困擾的魔咒


好問題。先回答為什麼會出現「燙燙燙」。

首先,這個現象只會在windows下用vs或者vc編程時才出現,並且只會出現在debug版本的運行過程中。如果在類unix系統下,使用gcc或者clang編譯器,你得到得通常會是提示segmentation fault.

vc或者vs在debug版本的程序初始化時,會將棧內未初始化的內存每個位元組設置成0xcc,這個代表的是一個特殊的中斷機器碼,int 3,準確地說是軟體調試中斷。注意,這裡的int是interrupt的意思,不是integer。將這些內存初始化成這個樣子是為了方便用戶進行斷點調試。

然而,當你的程序出現了訪問未出初始化的棧內存時,例如,數組越界,就會訪問這個特殊的位元組,如果你把它列印出來,通常會進行ascii碼的映射。可是,0xcc對應的十進位是204,然而ascii碼的範圍是0~127啊!所以,對於一個超過ascii碼錶示範圍的字元,程序通常會嘗試使用unicode編碼,unicode編碼是16位的,所以0xcc會被擴展稱為0xcccc,我們驗證一下「燙」的unicode編碼值:

怎麼不對呢?別急,我們猜測,中文字元通常會使用gbk編碼,那麼「燙」的gbk編碼是什麼呢?我們查一下:

果然沒錯!原來字元按照gbk編碼解析了。

現在回答樓主的問題,外國程序員會不會出現「燙燙燙」。

1. 首先如果不是用windows,不是用vs或者vc那麼不會出現。

2. 如果不是debug模式,也不會出現。通常會是亂碼。

以上的條件決定了編譯器是否會用0xcc填充非初始化棧內存。

3. 如果以上條件都滿足,那麼能不能出現燙要看你的編程環境和操作系統是否支持gbk編碼集,然而,大多數的英文操作系統並不默認支持。所以很可能還是按照unicode的方式去翻譯。

後記:「燙燙燙燙」是每一個在學校初學編程的學生都有的疑惑,代表了我們這些搞技術人青澀的過往,也是一段美好的回憶。貼張圖以表懷念。


我還出現過 傻傻傻傻傻傻 呢

那個時候剛剛開始學 不知道是不是在委婉的嘲諷我智商不足

這都被你發現了

AI要逆天了 摔


此答案是對@靈劍 的答案的一個補充。美國的程序員搞出來的「屯屯屯」如下:


總的來說,編碼格式搞錯了,就會出現這種問題

因為計算機只能處理數字,如果要處理文本,就必須先把文本轉換為數字才能處理。最早的計算機在設計時採用8個比特(bit)作為一個位元組(byte),所以,一個位元組能表示的最大的整數就是255(二進位11111111=十進位255),如果要表示更大的整數,就必須用更多的位元組。比如兩個位元組可以表示的最大整數是65535,4個位元組可以表示的最大整數是4294967295。

由於計算機是美國人發明的,因此,最早只有127個字母被編碼到計算機里,也就是大小寫英文字母、數字和一些符號,這個編碼表被稱為ASCII編碼,比如大寫字母A的編碼是65,小寫字母z的編碼是122。

但是要處理中文顯然一個位元組是不夠的,至少需要兩個位元組,而且還不能和ASCII編碼衝突,所以,中國制定了GB2312編碼,用來把中文編進去。

你可以想得到的是,全世界有上百種語言,日本把日文編到Shift_JIS里,韓國把韓文編到Euc-kr里,各國有各國的標準,就會不可避免地出現衝突,結果就是,在多語言混合的文本中,顯示出來會有亂碼。

因此,Unicode應運而生。Unicode把所有語言都統一到一套編碼里,這樣就不會再有亂碼問題了。

Unicode標準也在不斷發展,但最常用的是用兩個位元組表示一個字元(如果要用到非常偏僻的字元,就需要4個位元組)。現代操作系統和大多數編程語言都直接支持Unicode。

現在,捋一捋ASCII編碼和Unicode編碼的區別:ASCII編碼是1個位元組,而Unicode編碼通常是2個位元組。

字母A用ASCII編碼是十進位的65,二進位的01000001;

字元0用ASCII編碼是十進位的48,二進位的00110000,注意字元"0"和整數0是不同的;

漢字中已經超出了ASCII編碼的範圍,用Unicode編碼是十進位的20013,二進位的01001110 00101101。

你可以猜測,如果把ASCII編碼的A用Unicode編碼,只需要在前面補0就可以,因此,A的Unicode編碼是00000000 01000001。

新的問題又出現了:如果統一成Unicode編碼,亂碼問題從此消失了。但是,如果你寫的文本基本上全部是英文的話,用Unicode編碼比ASCII編碼需要多一倍的存儲空間,在存儲和傳輸上就十分不划算。

所以,本著節約的精神,又出現了把Unicode編碼轉化為「可變長編碼」的UTF-8編碼。UTF-8編碼把一個Unicode字元根據不同的數字大小編碼成1-6個位元組,常用的英文字母被編碼成1個位元組,漢字通常是3個位元組,只有很生僻的字元才會被編碼成4-6個位元組。如果你要傳輸的文本包含大量英文字元,用UTF-8編碼就能節省空間:

在計算機內存中,統一使用Unicode編碼,當需要保存到硬碟或者需要傳輸的時候,就轉換為UTF-8編碼。搞清楚了ASCII、Unicode和UTF-8的關係,我們就可以總結一下現在計算機系統通用的字元編碼工作方式:從上面的表格還可以發現,UTF-8編碼有一個額外的好處,就是ASCII編碼實際上可以被看成是UTF-8編碼的一部分,所以,大量只支持ASCII編碼的歷史遺留軟體可以在UTF-8編碼下繼續工作。

用記事本編輯的時候,從文件讀取的UTF-8字元被轉換為Unicode字元到內存里,編輯完成後,保存的時候再把Unicode轉換為UTF-8保存到文件:

瀏覽網頁的時候,伺服器會把動態生成的Unicode內容轉換為UTF-8再傳輸到瀏覽器:

所以你看到很多網頁的源碼上會有類似&的信息,表示該網頁正是用的UTF-8編碼。

reference:字元串和編碼


手持兩把錕斤拷。。


說起這個還得感謝燙燙燙燙

這學期C++考試有一道題怎麼做OJ都沒通過,結果運行一看輸出全是燙燙燙燙燙,瞬間知道自己數組越界了。馬上改過來。於是C++滿分通過


蒸蒸日上燙燙燙,年年有餘屯屯屯


他們會出現

ìììììììììì

一般他們喜歡把默認fallback編碼設置成微軟的編碼CP1252

控制台默認編碼會設置成CP437……


關於0xCCCCCCCC 知乎專欄


從C語的角度看要是你STRLEN的對像沒有結束符那麼列印出來的數劇就是內存中隨意的數據.配合你輸出的編碼格式.UT8 GDK什麼的,可能就會有這輸出了.


推薦閱讀:

使用codecs自定義編/解碼方案
拖尾的簡單實現
Python爬蟲實戰入門二:從一個簡單的HTTP請求開始
Fab Academy 第十六周:界面和應用編程
Haskell 這段代碼該如何理解?

TAG:編程 |