程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 淺談Unix和Linux下的int

淺談Unix和Linux下的int

編輯:關於C語言

這也算和平同學的點題作文了,呵呵。 他對於Linux下很多時候,api函數大量使用int作為常用類型感到不解,問我,我呢,就試著回答一下哈。 原帖在這裡:http://student.csdn.net/space.php?uid=121080&do=thread&id=9168 問題如下: 根據<c++ primer>建議,表示像“容量”這樣的變量時,因為不可能出現負數,所以建議用size_t類型。但是linux下的程序,好像比較喜歡使用int。 為什麼不使用size_t(或者unsigned int)而使用int?表示范圍不是少了一半嗎? 我的回答: 嗯,這個問題算是比較偏門了,不過,我做過Windows開發,也做過Linux開發,兩個平台都用過,沒什麼道理哈,僅僅談點自己的感覺,嗯,不一定准確,大家有高見,還可以補充。 我覺得這個問題首先是一個文化問題。什麼叫文化,就是做這類事情的人們的一個通常的共識,就是大家都習慣這麼做事。我很早,嗯,07年開始轉向Linux開發的時候,就發現這點不同。 Windows呢,是微軟公司開發的,大公司,強調嚴謹的開發風格,大家可以從它推崇匈牙利命名法就看的出來。它對於變量命名,類型命名是有嚴格規定的,要求盡量准確,不給後來者留歧義。比如,很多Struct*,它會使用typedef顯式定名為一種新類型PStruct來管理,這樣,大家從字面上就可以一眼看出來,而不用到用的時候,跑去數星星。數星星很容易數錯的。我就干過壞事,嘿嘿。 這個道理也很簡單,微軟是開發OS的,說白了,它的主要產品功能,除了Windows的操作功能,還需要提供大量的api給廣大程序員用,沒辦法啊,如果沒人給他的操作系統開發應用程序,他的OS賣不動的。 這就要求微軟不僅僅關注終端用戶的體驗,也特別關注程序員用戶的體驗,而明示的api,顯然是一種很好的用戶體驗,程序員不容易犯錯誤,被api的提供者約束著做正確的事情,程序員bug少,成功率就高,進而開發成本就低,於是,形成良性循環。 同時,這也為微軟的客服部門減少好多投訴哦,大家換位思考一下,如果微軟的api含糊不清,大家是不是要發飙?呵呵。 這裡面體現出來一個很重要的思想,微軟是把廣大應用程序員,也作為什麼都不懂的終端用戶在看待,試圖從api上構建最大的開發友好度,因此,它對於命名法很嚴格,api定名表意很清晰,同時,對於各種變量、類型,不厭其煩,多次定義,為了是讓各個行業的程序員, 用起來都盡量貼合自己的行業習慣。 這是有道理的,比如我現在在電力系統,我們定義變量類型,喜歡用Int16、Int32、Int64,Float16、Float32、Float64這類命名,int、double這些C/C++基本類型,反而不太流行。為啥,很多時候工業現場的人,不知道你這個類型到底是多少bits的,就會出錯。這是為了用戶看著清晰,也是行業習慣,所以,我很多時候開始寫程序前,都要先去定義這麼一批新的變量類型,方便和同事們溝通代碼啊。 而Unix呢,不太一樣,我看過《Unix編程藝術》這本書,這裡面講了很多Unix程序員的文化。這麼說吧,我簡單點,Unix的開發者,默認使用者是和其水平相當的程序員,大家所有溝通的語言,都是計算機本專業的,大家很多時候用默認,暗示,就好了。 所以,Unix下的習慣,沒有那麼多分門別類的變量類型,大家還有個好習慣,呵呵,int包打一切。我看到幾乎大多數Unix的函數,就是gcc的基本庫,函數老是int來,int去,其實,給我的感覺,在Unix下,什麼都是int,為啥,Unix很講究把同類資源數組化管理,比如打開的文件句柄,就是一個整數,進程ID,整數,線程ID,整數,用戶ID,整數,甚至,設備都是整數表示。嗯,socket不說了,Windows下是一個特定數據類型SOCKET,而Unix下,你猜對了,沒錯,int,整數。 這叫什麼?其實是向量化管理,在系統內部檢索的時候,可以想象,Unix系統的開發者,大量使用數組,利用int這個整數在哈希檢索目標,達到效率最高。反正,我們不管什麼資源,在Unix內部,就是一個int型的ID表示,這其實已經是Windows句柄的概念了。 這兩種命名方法,其實各有優缺點,Windows的變量類型多,程序員學習的時候,成本高,但是,學會了就不容易出錯。而Unix的學習曲線低,沒那麼多類型名要去背,不過呢,用起來出不出錯,自理啊,Unix的開發者,相信大家的實力。嗯,只是我自己有點信不過我自己,嘿嘿。 不過要我說呢,還真說不好誰對誰錯,其實都有道理,關鍵看OS的設計者,心目中的目標用戶的水平如何了。 回到和平同學的問題,用int,少一半,其實是有道理的,因為int是有符號的,有一半的表示范圍是負數,在表示很多容量的時候,比如說吧,malloc的數組,或者socket的表示范圍,確實負數沒有意義。因此,看起來被浪費了。 這其實不然,為什麼,原因很簡單。 int就算少一半,你能用多少?和平同學別見怪啊,我說句話,你問這個問題就表示還有點學生思維,總是想多多益善,就是我要把所有的資源都納入我的管理,呵呵。其實我們做工作做久了的,對於數據的邊界、范圍,反而有個思想,夠用就好,沒必要多。 int表示少一半,2G有吧,嗯,大多數用戶的數組,可不可能超過1G?其實,大多數時候,我們在這個地方用int,表示的范圍都很少的。少一半也夠用。socket不說了吧,理論上只有65536,int再少幾半也夠用,呵呵。 夠用就行了,不用擔心的,真要是需要用大表示,自己做unsigned long來表示,也是可以的。 而且,Unix這麼設計,有個最大的優點,就是數據的自描述特性得到了前所未有的發揮。我們都知道,在表示范圍、容量的時候,int只使用了正數部分,那負數部分做什麼?我來回答你,表示非法值,這個很重要。 試想一下,如果我們用的數據類型裡面,無法表示非法值,那麻煩了,api設計的時候,必須單獨設計一個參數,來傳遞非法值,這又涉及到&傳址調用,或者*直接傳指針調用,程序設計復雜度直線上升,設計的人也累,學的人也累,用起來更累。 這麼說可能不直觀,我舉個例子: 比如我要設計一個read函數,從某個文件id讀取一段數據,大家注意啊,Unix下,文件ID可以表示任何串行化設備的。包括socket,可以用resv這類伯克利socket api,也可以直接使用C基本庫的read,都對,因為使用int表示,Unix可以把所有串行化設備統一編址處理,用一類函數處理完。 函數原型我這麼設計,設計了兩個,大家比較一下: Code:

  1. int ReadFrom(int fd,char* szBuffer,int nBufferSizeMax);   
  2.   
  3. unsigned int ReadFrom(int fd,char* szBuffer,int nBufferSizeMax);   
可以吧,這雖然用了匈牙利命名法,但是,這是標准的C函數,沒錯吧。嗯,第一個應該是Unix的習慣,用int,第二個應該是Windows的習慣,用了無符號正整數,好,我們來看一種情況。 如果我們讀失敗了,要返回一個錯誤信息給上層調用者,怎麼辦? 第一個很簡單,由於其只使用了int的正數部分來表示讀成功多少字節,那好,-1來表示失敗就好了。 第二個就麻煩了,由於它只返回正整數,上層看見都都是對的,它沒有辦法返回一個錯誤標示。說白了,這個api設計很失敗,無法滿足所有的應用返回需求。那怎麼辦?也有兩種做法: Code:
  1. unsigned int ReadFrom(int fd,char* szBuffer,int nBufferSizeMax,bool& bSuccessFlag);   
  2. #define READ_FAIL 0xFFFFFFFF   
  3. //出錯返回READ_FAIL   
  4. unsigned int ReadFrom(int fd,char* szBuffer,int nBufferSizeMax);   
大家別說用0啊,很多時候,Read到0,不是錯誤,是一種正常的狀態,比如socker的read,read到0Bytes,很可能是對方沒有發送,並不是說socket失敗了,需要重建鏈路。 嗯,大家再來看看,第一種,沒辦法,只有多設計一個傳址的參數,讓函數返回是否成功讀取的標志,上層來決定怎麼處理。 第二種呢,顯式定義一個返回值為錯誤,這個返回值永遠不被理解為正確的值,就是正確業務不使用,僅供返回錯誤。 大家去比較一下Win32api,裡面很多用的都是第二種方法。 不過,這樣一來,大家覺得麻煩不麻煩,第一種,起碼要多做一個參數,程序員學習量增加,記住哦,一個函數好學,100個、1000個函數讓你背,你就覺得這個bSuccessFlag很討厭了。 第二個更無禮,首先,它限制了業務,導致了業務缺陷,至少,unsigned int表示的最大值,被用來做fail了,就是業務不能用了,其次,多了個宏,同樣的返回值unsigned int,需要區別對待,大家說用起來麻煩不麻煩? 別怕麻煩啊,呵呵,去看看Win32Socket的函數,它的SOCKET就是用了unsigned int表示的最大值,作為錯誤的SOCKET標識,其實就是按照上面第二種辦法設計的api,沒辦法,誰讓他把SOCKET定義為無符號正整數呢。自己給自己下絆子,呵呵。 嗯,還有什麼beginthreadex,CreateWindowsEx,這類函數,大家去看看HANDLE的數據定義,就知道為什麼參數設計得那麼繁瑣了。 很多時候,我們看api好用不好用,其實就看這些細節。 這裡多說一點吧,正是因為Unix和Linux下,很多api函數都用int做返回值,-1已經被公認為非法,失敗的標志,大家用起來反而簡單,一般說來,看見一個Unix的api函數,猜都猜得出它怎麼表示返回值,反正都是int嘛,-1就是失敗啦,0和正數都是成功。Windows下就麻煩了,查MSDN都要查半天,主要看它數據類型,以及相應的接口定義。 因此,別看Windows做了很多努力,做了很多程序員友好度的工作,有時候啊,我評論一句,還真不如Unix什麼都丟給程序員。 不過呢,也不好都說不對,如果應用程序員不是計算機界的專業人士,比如說,一個其他專業的工程師,需要臨時寫一小段程序解決個問題,Windows能保證他不出錯。為啥,數據類型定義錯了,編譯都過不去,自己查MSDN去。 所以,說來說去,我認為這個問題還是一個文化問題,兩種平台的開發文化,導致了今天的局面。說不上誰好誰壞。 大家看著用吧。 嗯,我私人呢,喜歡Windows的匈牙利命名法,喜歡嚴謹的定名,但是,不是很喜歡它那麼多數據類型,還是喜歡int,呵呵。 很多時候,我設計的api大家覺得有點怪,其實就來自於此,又用Windows的命名法,但是,api函數參數設計卻更靠Unix一些,算兩面的綜合吧。 《0bug-C/C++商用工程之道》裡面,我的工程庫用的就是我的習慣,兩種風格兼而有之,因為我覺得,不管白貓黑貓,抓到耗子就是好貓,哪個地方合用用哪個,哪個辦法合用用哪個,沒什麼門戶之見的。 這不絕對啊,上述僅僅是我個人的習慣,大家還是自己選合用的辦法好了,沒必要和我一樣。 =======================================================
在線底價購買《0bug-C/C++商用工程之道》
直接點擊下面鏈接或拷貝到浏覽器地址欄)
http://s.click.taobao.com/t_3?&p=mm_13866629_0_0&n=23&l=http%3A%2F%2Fsearch8.taobao.com%2Fbrowse%2F0%2Fn-g%2Corvv64tborsvwmjvgawdkmbqgboq---g%2Cgaqge5lhebbs6qzlfmqmttgtyo42jm6m22xllqa-------------1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20---40--coefp-0-all-0.htm%3Fpid%3Dmm_13866629_0_0 肖舸

本文出自 “肖舸的blog” 博客,請務必保留此出處http://tonyxiaohome.blog.51cto.com/925273/309032

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved