indows的变量类型多,程序员学习的时候,成本高,但是,学会了就不容易出错.而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:
- int ReadFrom(int fd,char* szBuffer,int nBufferSizeMax);
-
- unsigned int ReadFrom(int fd,char* szBuffer,int nBufferSizeMax);
可以吧,这虽然用了匈牙利命名法,但是,这是标准的C函数,没错吧.嗯,第一个应该是Unix的习惯,用int,第二个应该是Windows的习惯,用了无符号正整数,好,我们来看一种情况.
如果我们读失败了,要返回一个错误信息给上层调用者,怎么办?
第一个很简单, 其只使用了int的正数部分来表示读成功多少字节,那好,-1来表示失败就好了.
第二个就麻烦了, 它只返回正整数,上层看见都都是对的,它没有办法返回一个错误标示.说白了,这个api设计很失败,无法满足所有的应用返回需求.那怎么办?也有两种做法:
Code:
- unsigned int ReadFrom(int fd,char* szBuffer,int nBufferSizeMax,bool& bSuccessFlag);
- #define READ_FAIL 0xFFFFFFFF
-
- 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://search8.taobao.com/browse/0/n-g,orvv64tborsvwmjvgawdkmbqgboq---g,gaqge5lhebbs6qzlfmqmttgtyo42jm6m22xllqa-------------1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20---40--coefp-0-all-0.htm?pid=mm_13866629_0_0
肖舸
|