WEB开发网      婵犵數濮烽弫鍛婃叏閻戣棄鏋侀柛娑橈功缁犻箖鏌嶈閸撴氨鎹㈠☉娆愬闁告劕寮堕幖鎰棯閸撗勫殌闁宠鍨块幃鈺冣偓鍦Т椤ユ繈姊哄Ч鍥р偓妤呭磻閹捐桅闁告洦鍨扮粻娑㈡煕椤愶絾绀冩い搴$Ч濮婅櫣绮欏▎鎯у壋闂佸摜濮甸崝娆愪繆閻㈢ǹ绀嬫い鏍ㄨ壘閸炪劑姊洪棃娴ゆ稒鎷呴幓鎺嶅闂佸湱鍎ら〃鍡涘煕閹烘鐓曢柡鍥ュ妼娴滄粍銇勮箛锝呭籍闁哄备鈧磭鏆嗛悗锝庡墰閺嗙娀鏌ф导娆戝埌闁靛棙甯掗~婵嬫偂鎼达絼鐢荤紓浣诡殕閸ㄥ灝顫忕紒妯诲缂佹稑顑呭▓顓炩攽椤旀枻鍏紒鐘虫崌閵嗕礁顫濋幇浣光枌婵犵數濮崑鎾趁归敐鍥┿€婇柡鈧禒瀣厽婵☆垱顑欓崵瀣偓瑙勬偠閸庤精鐏冮梺缁樏鍫曞疮閻愮數纾奸柛灞炬皑鏁堥悗瑙勬礃缁繘藝鐎靛摜妫柟顖嗕礁浠悗娈垮枛閻栫厧鐣烽悡搴樻婵☆垯璀﹂悗宕囩磽閸屾瑧鍔嶆い銊ユ閻f繈骞栨担姝屾憰闂佺粯妫冮ˉ鎾诲汲鐎n喗鐓熸俊銈傚亾闁绘妫楅埢鎾澄旈崨顔规嫼闁荤姴娲犻埀顒冩珪閻忊偓闂備礁鎼幊鎰叏閹绢喗鍋╅柣銈庡灛娴滃綊鏌熼悜妯肩畺闁哄懏绻堝娲濞戞艾顣哄┑鈽嗗亝閻熲晠銆佸▎鎺旂杸闁哄啫鍊婚惁鍫ユ⒑濮瑰洤鐏叉繛浣冲嫮顩烽柨鏇炲€归悡鏇㈡煏婵炲灝鍔ら柛鈺嬬稻椤ㄣ儵鎮欓弶鎴濐潚濡ょ姷鍋為敃銏ゃ€佸▎鎾村殐闁冲搫顑囬獮銏ゆ⒒閸屾瑦绁版い顐㈩槸閻e嘲螣閼测晝鐓嬪銈嗘閿熴儲绂嶈ぐ鎺撶厵闁绘垶蓱鐏忣厼霉濠婂啰绉烘慨濠呮缁辨帒螣閾忛€涙闂備焦瀵уú宥夊疾濞戞粎浜遍梻浣告啞濞诧箓宕归柆宥呯厱闁硅揪闄勯悡娆撴煠濞村娅呭ù鐘崇矊閳规垿鍨鹃悙钘変划闂佽鍠楅〃鍛村煡婢舵劕绠抽柟鎯ь嚟瑜板洨绱撻崒娆戣窗闁哥姵鐗犻、鏍川閹碱厽鏅i梺绋跨箳閸樠呮閻愮繝绻嗘い鏍ㄧ矌鐢稒绻涢崨顓熷枠婵﹦绮幏鍛存偡闁箑娈濈紓鍌欐祰椤曆囧磹閸噮鍤曠紓浣贯缚缁♀偓闂佹悶鍎崝宥呪枍閸ヮ剚鈷戠紒瀣濠€鎵磼鐎n偅宕岀€规洏鍨介幃浠嬪川婵犲嫬骞楅梺鐟板悑閻n亪宕规繝姘厐闁哄洢鍨洪悡銉︽叏濡灝鐓愰柣鎾跺枛閻擃偊宕堕妷銉ュБ缂備礁顑堝畷鐢垫閹烘梻纾兼俊顖濆亹閻h櫣绱撴担铏瑰笡缂佽鐗嗛悾宄邦潨閳ь剚淇婂宀婃Ш缂備浇椴哥换鍫濐潖缂佹ɑ濯寸紒娑橆儏濞堟劙姊洪幖鐐插闁告鍟块悾鐑筋敍閻愯尙楠囬梺鐟邦嚟婵潧鈻撴ィ鍐┾拺缂備焦蓱閳锋帡鏌嶅畡鎵ⅵ鐎殿噮鍋婂畷鎺楁倷鐎电ǹ骞堥梻浣瑰▕閺侇噣宕戦幘缁樼厸闁告侗鍠氶幊鍛繆閸欏濮囬摶锝夋偠濞戞帒澧查柡鍌楀亾闂傚倷鑳剁划顖炲礉閺囩倣鐔哥節閸パ冩優闂佺粯鏌ㄩ惃婵嬪绩閼恒儯浜滈柡鍐ㄦ处椤ュ鏌涢弬璇测偓婵嬪箺閸洘鍊烽柣鎴炨缚閸橀亶姊洪崫鍕偍闁告柨鏈弲鍫曨敍閻愬鍘卞┑鐐叉缁绘帞绮绘繝姘厸閻忕偟鏅晥閻庤娲﹂崑濠傜暦閻旂⒈鏁嗛柍褜鍓欓埢宥夋晲閸モ晝锛濇繛杈剧稻瑜板啯绂嶉悙顒傜瘈闁靛骏绲剧涵鐐亜閹存繃宸濈紒顔剧帛閵堬綁宕橀埡鍐ㄥ箥闂佽瀛╃粙鎺戠幓鐠恒劎涓嶆慨妞诲亾闁哄被鍔岄埥澶娢熸径鐧哥稻閵囧嫰濡搁敐鍛Е闂佽鍠楅悷鈺呫€侀弮鍫濈妞ゆ挻绻勭粈鍕⒒閸屾瑦绁版い鏇熺墵瀹曚即寮介銈囶槸婵犵數濮撮崐濠氬汲閿曞倹鐓欐い鏍仜娴滅増淇婇懠棰濆殭闁宠鍨块崺鍕礃閵娧呫偡婵$偑鍊ら崢楣冨礂濡警鍤曢悹鍥ㄧゴ濡插牓鏌曡箛鏇烆潔闁冲搫鎳忛悡蹇擃熆鐠鸿櫣澧曢柛鏃€鎸抽弻娑㈠棘濞嗙偓楔缂備浇椴搁幐濠氬箯閸涱垳鐭欓幖瀛樻尭娴滈箖鏌涘┑鍕姢闁活厽鎸鹃幉鎼佹偋閸繄鐟ㄩ梺鍝勵儎缁舵岸寮婚悢鐓庣鐟滃繒鏁☉銏$厸闁告侗鍠楅崐鎰版煛鐏炶濮傞柟顔哄€濆畷鎺戔槈濮楀棔绱� ---闂傚倸鍊搁崐鎼佸磹閹间礁纾归柣鎴eГ閸婂潡鏌ㄩ弮鍫熸殰闁稿鎸剧划顓炩槈濡搫绠诲┑鐐叉▕娴滄粓鎮″☉銏$厱婵炴垵宕獮妯汇亜閺傛寧顥㈡慨濠呮閹瑰嫰濡搁妷锔惧綒闂備胶鎳撻崵鏍箯閿燂拷
开发学院软件开发C++ 精华:C++编程新手错误语录(续一) 阅读

精华:C++编程新手错误语录(续一)

 2008-03-08 21:35:53 来源:WEB开发网 闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣椤愯姤鎱ㄥ鍡楀幊缂傚倹姘ㄩ幉绋款吋閸澀缃曢梻鍌欑濠€閬嶆惞鎼淬劌绐楅柡宥庡亞娑撳秵銇勯弽顐沪闁绘挶鍎甸弻锝夊即閻愭祴鍋撻崷顓涘亾濮樼偓瀚�闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣捣閻棗銆掑锝呬壕濡ょ姷鍋涢ˇ鐢稿极閹剧粯鍋愰柟缁樺笧閳ь剦鍙冨鍝勑ч崶褏浠奸梺璇茬箲閼归箖鎮鹃悜钘夎摕闁靛濡囬崢鐢告⒑鐟欏嫷鍟忛柛鐘崇墵閵嗗倹绺介崨濠勫幈闁硅壈鎻槐鏇熺墡闂備線娼уú銈団偓姘嵆閻涱噣骞掑Δ鈧粻锝嗙節闂堟稑鏆欏ù婊堢畺閺岋綁濮€閳惰泛婀辨竟鏇熺節濮橆厾鍘甸梺缁樺姦閸撴岸鎮樻潏銊ょ箚闁圭粯甯炴晶娑氱磼缂佹ḿ娲寸€规洖宕灃闁告劕鍟犻崜婵堟崲濞戞ḿ鏆嗗┑鐘辫兌閺佹牜绱撴担浠嬪摵闁圭懓娲ら悾鐑藉箳閹搭厽鍍甸梺鐟板悁閻掞箓鎮楅幖浣光拻濞达絿鍎ら崵鈧梺鎼炲€栭悧鐘荤嵁韫囨稒鏅搁柨鐕傛嫹婵犵數濮烽弫鍛婃叏閻戣棄鏋侀柛娑橈攻閸欏繑銇勯幘鍗炵仼缂佺媭鍨堕弻娑㈠箛闂堟稒鐏堥悗鐟版啞缁诲啴濡甸崟顖氱閻庨潧鎽滈悾濂告⒑绾拋娼愭繛鑼枎椤繒绱掑Ο鑲╂嚌闂侀€炲苯澧畝锝堝劵椤︽煡鎮¢妶澶嬬厪闁割偅绻冮崑顏呯箾瀹割喕绨婚幆鐔兼⒑鐎圭姵銆冮柤鍐茬埣瀹曟繈鏁冮埀顒勨€旈崘顔嘉ч柛鈩冾殘閻熸劙姊洪悡搴℃毐闁绘牕銈稿畷鐑樼節閸パ冨祮闂侀潧楠忕槐鏇㈠储椤忓牊鈷戦柟鑲╁仜閸旀鏌¢崨顔锯姇缂佸倹甯熼ˇ瀵哥磼鏉堛劌绗氭繛鐓庣箻閸┾剝鎷呴柨瀣垫綗闂傚倷娴囧銊╂倿閿曞倸绠查柛銉墮閺嬩線鏌熼崜褏甯涢柡鍛倐閺屻劑鎮ら崒娑橆伓闂傚倸鍊搁崐鎼佸磹閹间礁纾瑰瀣椤愯姤鎱ㄥ鍡楀幊缂傚倹姘ㄩ幉绋款吋閸澀缃曢梻鍌欑濠€閬嶆惞鎼淬劌绐楅柡宥庡亞娑撳秵銇勯弽顐沪闁绘挶鍎甸弻锝夊即閻愭祴鍋撻崷顓涘亾濮樼偓瀚�  闂傚倸鍊搁崐鎼佸磹閹间礁纾归柣鎴eГ閸ゅ嫰鏌ら崫銉︽毄濞寸姵姘ㄧ槐鎾诲磼濞嗘帒鍘$紓渚囧櫘閸ㄥ爼濡撮崘顔煎窛闁哄鍨归崢娲倵楠炲灝鍔氭い锔诲灦瀹曪繝骞庨懞銉у帾闂婎偄娲﹀ú鏍ㄧ墡闂備浇顕х€垫帡宕滈悢濂夋綎闁惧繐婀辩壕鍏间繆椤栨碍鎯堟い顐㈢Т椤啴濡堕崱妤€顫庨梺鍛婎焼閸パ呭弨婵犮垼娉涜癌闁绘柨鍚嬮悡銉╂倵閿濆骸鍘撮柛瀣尰缁绘繂顫濋娑欏闁荤喐绮庢晶妤冩暜閹烘挾顩插ù鐓庣摠閻撴洟鏌熼幆褜鍤熼柍钘夘樀閺屽秶绱掑Ο鑽ゅ弳濡炪値鍋呯换鍫ュ箠濠婂懎鏋堟俊顖濐嚙椤忓綊姊婚崒娆戭槮闁硅绱曠划娆撳箣閿斿搫浜奸梺鍝勵槹閸ㄧ喖寮搁弮鍫熺厸闁告劧绲芥禍鍓х磽娴h櫣甯涚紒瀣尰缁傛帡鏁冮崒姘憋紲濠殿喗锕╅崜锕傛倵閹惰姤鈷掑ù锝呮憸閿涘秶绱掗鍛仸妤犵偞鍨垮畷鍫曨敆閸屾氨銈﹂梺璇插嚱缂嶅棙绂嶉弽顓炵哗濞寸姴顑嗛悡娆撴⒑椤撱劎鐣卞褜鍨遍妵鍕棘閸喒鍋撶憴鍕攳濠电姴娲﹂崐閿嬨亜韫囨挸顏ら柛瀣崌瀵€燁檨婵炲吋鐗曢埞鎴︽偐鐎圭姴顥濋梺绋胯閸斿酣骞夊宀€鐤€婵炴垶岣块悿鍛存⒑閸︻叀妾搁柛鐘愁殜瀵煡骞栨担鍦弳闂佺粯娲栭崐鍦偓姘炬嫹
核心提示:废话不说,直接进入正题,精华:C++编程新手错误语录(续一),本文承接先前发布的《C/C++编程新手错误语录》(http://www.pconline.com.cn/pcedu/empolder/gj/c/0508/691597.Html),继续归纳错误语录,更多错误语录,当然是待续,
  废话不说,直接进入正题,本文承接先前发布的《C/C++编程新手错误语录》(http://www.pconline.com.cn/pcedu/empolder/gj/c/0508/691597.Html),继续归纳错误语录。 (8)“我想用malloc”、“我用不好malloc”
  来看看一个变态程序:
/* xx.c:xx模块实现文件 */
int *pInt;
/* xx模块的初始化函数 */
xx_intial()
{
pInt = ( int * ) malloc ( sizeof( int ) );
...
}
/* xx模块的其他函数(仅为举例)*/
xx_otherFunction()
{
*Int = 10;
...
}
  这个程序定义了一个全局整型变量指针,在xx模块的初始化函数中对此指针动态申请内存,并将pInt指向该内存首地址,并在xx模块的其他函数中都使用pInt指针对其指向的整数进行读取和赋值。

  这个程序让我痛不欲生了好多天,扼腕叹息!这是我母校计算机系一位硕士的作品!作者为了用上malloc,拼命地把本来应该用一个全局整型变量摆平的程序活活弄成一个全局整型指针并在初始化函数中“动态”申请内存,自作聪明而正好暴露自己的无知!我再也不要见到这样的程序。

  那么malloc究竟应该怎么用?笔者给出如下规则:
  规则1 不要为了用malloc而用malloc,malloc不是目的,而是手段;

  规则2 malloc的真正内涵体现在“动态”申请,假如程序的特性不需动态申请,请不要用malloc;

  上面列举的变态程序完全不具备需要动态申请的特质,应该改为:
/* xx.c:xx模块实现文件 */
int example;
/* xx模块的初始化函数 */
xx_intial()
{
...
}
/* xx模块的其他函数(仅为举例) */
xx_otherFunction()
{
example = 10;
...
}
更多文章 更多内容请看C/C++技术专题 java编程开发手册专题,或
  规则3 什么样的程序具备需要动态申请内存的特质呢?包含两种情况:
  (1)不知道有多少要来,来了的又走了
  不明白?这么说吧,譬如你正在处理一个报文队列,收到的报文你都存入该队列,处理完队列头的报文后你需要取出队列头的元素。

  你不知道有多少报文来(因而你不知道应该用多大的报文数组),这些来的报文处理完后都要走(释放),这种情况适合用malloc和free。

  (2)慢慢地长大
  譬如你在资源受限的系统中编写一文本编辑器程序,你怎么做,你需要这样定义数组吗?
  char str[10000];  不,你完全不应该这么做。即使你定义了一个10000字节大的字符串,用户假如输入10001个字符你的程序就完完了。

  这个时候适合用malloc,因为你根本就不知道用户会输入多少字符,文本在慢慢长大,因而你也应慢慢地申请内存,用一个队列把字符串存放起来。

  那么是不是应该这样定义数据结构并在用户每输入一个字符的情况下malloc一个CharQueue空间呢?
typedef strUCt tagCharQueue

{
char ch;
struct tagCharQueue *next;
}CharQueue;
  不,这样做也不对!这将使每个字符占据“1+指针长度”的开销。

  正确的做法是:
typedef struct tagCharQueue
{
char str[100];
struct tagCharQueue *next;
}CharQueue;
  让字符以100为单位慢慢地走,当输入字符数达到100的整数倍时,申请一片CharQueue空间。

更多文章 更多内容请看C/C++技术专题 Java编程开发手册专题,或
  规则4 malloc与free要成对出现
  它们是一对恩爱夫妻,malloc少了free就必然会慢慢地死掉。成对出现不仅体现在有多少个malloc就应该有多少个free,还体现在它们应尽量出现在同一函数里,“谁申请,就由谁释放”,看下面的程序:
char * func(void)
{
char *p;
p = (char *)malloc(…);
if(p!=NULL)
…; /* 一系列针对p的操作 */
return p;
}
/*在某处调用func(),用完func中动态申请的内存后将其free*/
char *q = func();

free(q);
  上述代码违反了malloc和free的“谁申请,就由谁释放”原则,代码的耦合度大,用户在调用func函数时需确切知道其内部细节!正确的做法是:
/* 在调用处申请内存,并传入func函数 */
char *p=malloc(…);
if(p!=NULL)
{
func(p);

free(p);
p=NULL;
}
/* 函数func则接收参数p */
void func(char *p)
{
… /* 一系列针对p的操作 */
}
  规则5 free后一定要置指针为NULL,防止其成为“野”指针

(9)“函数add编译生成的符号就是add”
int add(int x,int y)
{
return x + y;
}
float add(float x,float y)
{
return x + y;
}
更多文章 更多内容请看C/C++技术专题 Java编程开发手册专题,或
  即便是在C语言中,add函数被多数C编译器编译后在符号库中的名字也不是add,而是_add。 而在C++编译器中,int add(int x,int y)会编译成类似_add_int_int这样的名字(称为“mangled name”),float add(float x,float y)则被编译成_add_float _float,mangled name包含了函数名、函数参数数量及类型信息,C++依靠这种机制来实现函数重载。

  所以,在C++中,本质上int add( int x, int y )与float add( float x, float y )是两个完全不同的函数,只是在用户看来其同名而已。

  这就要求初学者们能透过语法现象看问题本质。本质上,语言的创造者们就是在玩各种各样的花样,以使语言具备某种能力,譬如mangled name花样的目的在于使C++支持重载。而C语言没有玩这样的花样,所以int add( int x, int y )与float add( float x, float y )不能在C程序中同时存在。

(10)“没见过在C语言中调用C++的函数”、“C/C++不能调用Basic、Pascal语言的函数”
  这又是一个奇天下之大怪的问题,“打死我都不相信C、C++、basic、pascal的函数能瞎调来调去”,可是有句话这么说:
  没有你见不到的,只有你想不到的!

  既然芙蓉姐姐也有其闻名天下的道理,那么C、C++、Basic、Pascal的函数为什么就不能互相调用呢?
  能!

  你可以用Visual C++写一个DLL在Visual Basic、Delphi(Pascal的孙子,Object Pascal的儿子)中调用,也可以在Visual Basic、Delphi中写一个DLL在Visual C++中调用不是?


  让我们来透过现象看本质。首先看看函数的调用约定(以Visual C++来说明):
  (1) _stdcall调用
  _stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。
  WIN32 Api都采用_stdcall调用方式,这样的宏定义说明了问题:
  #define WINAPI _stdcall  按C编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionname@number。

更多文章 更多内容请看C/C++技术专题 Java编程开发手册专题,或
  (2) _cdecl调用
  _cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护。_cedcl约定的函数只能被C/C++调用,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。

  由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定。关于C/C++中变长参数(…)的问题,笔者将另文详述。

  由于Visual C++默认采用_cdecl 调用方式,所以VC中中调用DLL时,用户应使用_stdcall调用约定。
  按C编译方式,_cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。

  (3) _fastcall调用
  _fastcall调用较快,它通过CPU内部寄存器传递参数。

  按C编译方式,_fastcall调用约定在输出函数名前面加“@”符号,后面加“@”符号和参数的字节数,形如@functionname@number。

  要害字_stdcall、_cdecl和_fastcall可以直接加在函数前,也可以在Visual C++中设置,如图1。
精华:C++编程新手错误语录(续一)  图1 在VC中设置函数调用约定  在创建DLL时,一般使用_stdcall调用(Win32 Api方式),采用_functionname@number命名规则,因而各种语言间的DLL能互相调用。也就是说,DLL的编制与具体的编程语言及编译器无关,只要遵守DLL的开发规范和编程策略,并安排正确的调用接口,不管用何种编程语言编制的DLL都具有通用性。

  推而广之,假如有这样一个IDE开发环境,它能识别各种语言,所有语言采用相同的调用约定和命名规则,一个软件内各种语言书写的函数将能互相调用!

  这个世界上可能永远不需要这样一个IDE。

(11)“英语、数学不好就学不好C/C++”
更多文章 更多内容请看C/C++技术专题 Java编程开发手册专题,或
  这也许是20世纪最大的谎言,这句话最先是哪位大师的名人名言已无可考证,可此后一批批的人被它误导。许多初学者因为这句话被吓倒,放弃了做程序员的理想。 还有许多后来成为优秀程序员的人,在他们的成长过程中并没有依靠深奥的数学,可他们还是在总结经验时制造恐慌,号称一定要具备高深的数学知识,唯恐别人笑话其学术水平不高。

  在下则认为,大多数情况下,程序设计不需要太深奥的数学功底,除非你所从事的程序设计涉及特定的专业领域(如语音及图像处理、数字通信技术等)。在下这一观点也许是革旧立新,而革命必然要流血牺牲(谭嗣同),所以恭候大家板砖。

  那么英语在C/C++的学习中处于什么地位呢?那就是能看懂资料,看懂MSDN。

  学编程的终极之道不在看书,而在大量地不断地实践。

(12)“C++太难了,我学不会”

  又不知是谁的悲观论调,许多初学者被C++吓倒,“太难了,我学不好”,如弱者自怜。假如C++真的难到学不会,那么C++的创造者们所从事的工作岂不是“非人力所能及也”?  
 
  在下认为,学习C++的态度应该是:战略上藐视它,战术上重视它,要敢于胜利(《毛主席语录》)。当然也不可轻敌,不能因为把握了一点皮毛就以为自己牛B轰轰了(笔者曾经牛B轰轰了好一阵子,现在想来,甚觉当时幼稚)。

  假如你征服了C++,透彻理解了C++的语言特性及STL,那么,其他语言想不被你征服都难了。

  本回书着落此处,更多错误语录,当然是待续。
更多文章 更多内容请看C/C++技术专题 Java编程开发手册专题,或

Tags:精华 编程 新手

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接