十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
在我的整個(gè)職業(yè)生涯里我都在使用C++,而且現(xiàn)在C++依然是我做大多數(shù)項(xiàng)目時(shí)的首選編程語(yǔ)言。自然的,當(dāng)我從2007年開(kāi)始做ZeroMQ(ZeroMQ項(xiàng)目主頁(yè))時(shí),我選擇用C++來(lái)實(shí)現(xiàn)。主要的原因有以下幾點(diǎn):1. 包含數(shù)據(jù)結(jié)構(gòu)和算法的庫(kù)(STL)已經(jīng)成為這個(gè)語(yǔ)言的一部分了。如果用C,我將要么依賴第三方庫(kù)要么不得不自己手動(dòng)寫一些自1970年來(lái)就早已存在的基礎(chǔ)算法。2. C++語(yǔ)言本身在編碼風(fēng)格的一致性上起到了一些強(qiáng)制作用。比如,有了隱式的this指針參數(shù),這就不允許通過(guò)各種不同的方式將指向?qū)ο蟮闹羔樧鲛D(zhuǎn)換,而那種做法在C項(xiàng)目中常常見(jiàn)到(通過(guò)各種類型轉(zhuǎn)換)。同樣的還有可以顯式的將成員變量定義為私有的,以及許多其他的語(yǔ)言特性。3. 這個(gè)觀點(diǎn)基本上是前一個(gè)的子集,但值得我在這里顯式的指出:用C語(yǔ)言實(shí)現(xiàn)虛函數(shù)機(jī)制比較復(fù)雜,而且對(duì)于每個(gè)類來(lái)說(shuō)會(huì)有些許的不同,這使得對(duì)代碼的理解和維護(hù)都會(huì)成為痛苦之源。4. 最后一點(diǎn)是:人人都喜歡析構(gòu)函數(shù),它能在變量離開(kāi)其作用域時(shí)自動(dòng)得到調(diào)用。如今,5年過(guò)去了,我想公開(kāi)承認(rèn):用C++作為ZeroMQ的開(kāi)發(fā)語(yǔ)言是一個(gè)糟糕的選擇,后面我將一一解釋為什么我會(huì)這么認(rèn)為。首先,很重要的一點(diǎn)是ZeroMQ是需要長(zhǎng)期連續(xù)不停運(yùn)行的一個(gè)網(wǎng)絡(luò)庫(kù)。它應(yīng)該永遠(yuǎn)不會(huì)出錯(cuò),而且永遠(yuǎn)不能出現(xiàn)未定義的行為。因此,錯(cuò)誤處理對(duì)于ZeroMQ來(lái)說(shuō)至關(guān)重要,錯(cuò)誤處理必須是非常明確的而且對(duì)錯(cuò)誤應(yīng)該是零容忍的。C++的異常處理機(jī)制卻無(wú)法滿足這個(gè)要求。C++的異常機(jī)制對(duì)于確保程序不會(huì)失敗是非常有效的——只要將主函數(shù)包裝在try/catch塊中,然后你就可以在一個(gè)單獨(dú)的位置處理所有的錯(cuò)誤。然而,當(dāng)你的目標(biāo)是確保沒(méi)有未定義行為發(fā)生時(shí),噩夢(mèng)就產(chǎn)生了。C++中引發(fā)異常和處理異常是松耦合的,這使得在 C++中避免錯(cuò)誤是十分容易的,但卻使得保證程序永遠(yuǎn)不會(huì)出現(xiàn)未定義行為變得基本不可能。在C語(yǔ)言中,引發(fā)錯(cuò)誤和處理錯(cuò)誤的部分是緊耦合的,它們?cè)谠创a中處于同一個(gè)位置。這使得我們?cè)阱e(cuò)誤發(fā)生時(shí)能很容易理解到底發(fā)生了什么:int rc = fx (); if (rc != 0) handle_error();在C++中,你只是拋出一個(gè)異常,到底發(fā)生了什么并不能馬上得知。int rc = fx(); if (rc != 0) throw std::exception();這里的問(wèn)題就在于你對(duì)于誰(shuí)處理這個(gè)異常,以及在哪里處理這個(gè)異常是不得而知的。如果你把異常處理代碼也放在同一個(gè)函數(shù)中,這么做或多或少還有些明智,盡管這么做會(huì)犧牲一點(diǎn)可讀性。try { … int rc = fx(); if (rc != 0) throw std::exception(“Error!”); … catch (std::exception e) { handle_exception(); }但是,考慮一下,如果同一個(gè)函數(shù)中拋出了兩個(gè)異常時(shí)會(huì)發(fā)生什么?class exception1 {}; class exception2 {}; try { … if (condition1) throw my_exception1(); … if (condition2) throw my_exception2(); … } catch (my_exception1 e) { handle_exception1(); } catch (my_exception2 e) { handle_exception2(); }對(duì)比一下相同的C代碼:… if (condition1) handle_exception1(); … if (condition2) handle_exception2(); …C代碼的可讀性明顯高的多,而且還有一個(gè)附加的優(yōu)勢(shì)——編譯器會(huì)為此產(chǎn)生更高效的代碼。這還沒(méi)完呢。再考慮一下這種情況:異常并不是由所拋出異常的函數(shù)來(lái)處理。在這種情況下,異常處理可能發(fā)生在任何地方,這取決于這個(gè)函數(shù)是在哪調(diào)用的。雖然乍一看我們可以在不同的上下文中處理不同的異常,這似乎很有用,但很快就會(huì)變成一場(chǎng)噩夢(mèng)。當(dāng)你在解決bug的時(shí)候,你會(huì)發(fā)現(xiàn)幾乎同樣的錯(cuò)誤處理代碼在許多地方都出現(xiàn)過(guò)。在代碼中增加一個(gè)新的函數(shù)調(diào)用可能會(huì)引入新的麻煩,不同類型的異常都會(huì)涌到調(diào)用函數(shù)這里,而調(diào)用函數(shù)本身并沒(méi)有適當(dāng)進(jìn)行的處理,這意味著什么?新的bug。如果你依然堅(jiān)持要杜絕“未定義的行為”,你不得不引入新的異常類型來(lái)區(qū)分不同的錯(cuò)誤模式。然而,增加一個(gè)新的異常類型意味著它會(huì)涌現(xiàn)在各個(gè)不同的地方,那么就需要在所有這些地方都增加一些處理代碼,否則你又會(huì)出現(xiàn)“未定義的行為”。到這里你可能會(huì)尖叫:這特么算什么異常規(guī)范哪!好吧,問(wèn)題就在于異常規(guī)范只是以一種更加系統(tǒng)化的方式,以按照指數(shù)規(guī)模增長(zhǎng)的異常處理代碼來(lái)處理問(wèn)題的工具,它并沒(méi)有解決問(wèn)題本身。甚至可以說(shuō)現(xiàn)在情況更加糟糕了,因?yàn)槟悴坏貌蝗懶碌漠惓n愋停碌漠惓L幚泶a,以及新的異常規(guī)范。通過(guò)上面我描述的問(wèn)題,我決定使用去掉異常處理機(jī)制的C++。這正是ZeroMQ以及Crossroads I/O今天的樣子。但是,很不幸,問(wèn)題到這并沒(méi)有結(jié)束…考慮一下當(dāng)一個(gè)對(duì)象初始化失敗的情況。構(gòu)造函數(shù)沒(méi)有返回值,因此出錯(cuò)時(shí)只能通過(guò)拋出異常來(lái)通知出現(xiàn)了錯(cuò)誤。可是我已經(jīng)決定不使用異常了,那么我不得不這樣做:class foo { public: foo(); int init(); … };當(dāng)你創(chuàng)建這個(gè)類的實(shí)例時(shí),構(gòu)造函數(shù)被調(diào)用(不允許失?。缓竽泔@式的去調(diào)用init來(lái)初始化(init可能會(huì)失?。?duì)象。相比于C語(yǔ)言中的做法,這就顯得過(guò)于復(fù)雜了。struct foo { … }; int foo_init(struct foo *self);但是以上的例子中,C++版本真正邪惡的地方在于:如果有程序員往構(gòu)造函數(shù)中加入了一些真正的代碼,而不是將構(gòu)造函數(shù)留空時(shí)會(huì)發(fā)生什么?如果有人真的這么做了,那么就會(huì)出現(xiàn)一個(gè)新的特殊的對(duì)象狀態(tài)——“半初始化狀態(tài)”。這種狀態(tài)是指對(duì)象已經(jīng)完成了構(gòu)造(構(gòu)造函數(shù)調(diào)用完成,且沒(méi)有失?。?,但init函數(shù)還沒(méi)有被調(diào)用。我們的對(duì)象需要修改(特別是析構(gòu)函數(shù)),這里應(yīng)該以一種方式妥善的處理這種新的狀態(tài),這就意味著又要為每一個(gè)方法增加新的條件??吹竭@里你可能會(huì)說(shuō):這就是你人為的限制使用異常處理所帶來(lái)的后果啊!如果在構(gòu)造函數(shù)中拋出異常,C++運(yùn)行時(shí)庫(kù)會(huì)負(fù)責(zé)清理適當(dāng)?shù)膶?duì)象,那這里根本就沒(méi)有什么“半初始化狀態(tài)”了!很好,你說(shuō)的很對(duì),但這根本無(wú)關(guān)緊要。如果你使用異常,你就不得不處理所有那些與異常相關(guān)的復(fù)雜情況(我前面已經(jīng)描述過(guò)了)。而這對(duì)于一個(gè)面對(duì)錯(cuò)誤時(shí)需要非常健壯的基礎(chǔ)組件來(lái)說(shuō)并不是一個(gè)合理的選擇。此外,就算初始化不是問(wèn)題,那析構(gòu)的時(shí)候絕對(duì)會(huì)有問(wèn)題。
創(chuàng)新互聯(lián)科技有限公司專業(yè)互聯(lián)網(wǎng)基礎(chǔ)服務(wù)商,為您提供服務(wù)器托管,高防服務(wù)器,成都IDC機(jī)房托管,成都主機(jī)托管等互聯(lián)網(wǎng)服務(wù)。
#include stdio.h
#include stdlib.h
//節(jié)點(diǎn)結(jié)構(gòu)
struct queue{
int num;
struct queue *next;
};
//創(chuàng)建空鏈表
struct queue *initque(void)
{
struct queue *q;
q=(struct queue *)malloc(sizeof(struct queue));
q-next=NULL; //頭結(jié)點(diǎn)啥也沒(méi)有
return q;
}
//隊(duì)列尾部添加數(shù)據(jù)
void addnum(struct queue * const q,int a)
{
struct queue *n;
struct queue *tmpq=q;//一個(gè)會(huì)移動(dòng)的指針
n=(struct queue *)malloc(sizeof(struct queue));//新創(chuàng)建個(gè)節(jié)點(diǎn)存儲(chǔ)值
n-num=a;
n-next=NULL;
while(tmpq-next!=NULL)
tmpq=tmpq-next;
tmpq-next=n;//把新建的節(jié)點(diǎn)追加到鏈表末尾
}
//刪除節(jié)點(diǎn)
int delnum(struct queue * const q)
{
int i;
struct queue *current;
struct queue *tmpq=q;
if(tmpq-next!=NULL)
{
current=tmpq-next;//頭結(jié)點(diǎn)的下一結(jié)點(diǎn),要?jiǎng)h除的節(jié)點(diǎn)
tmpq-next=current-next;//頭結(jié)點(diǎn)跳過(guò)要?jiǎng)h除的結(jié)點(diǎn)指向下一結(jié)點(diǎn)
i=current-num;
free(current);
return i;//返回節(jié)點(diǎn)的值
}
return -1;
}
int main(void)
{
struct queue *myq;
myq=initque();
addnum(myq,1);
addnum(myq,3);
addnum(myq,5);
addnum(myq,7);
addnum(myq,9);
printf("%d\n",delnum(myq));
printf("%d\n",delnum(myq));
printf("%d\n",delnum(myq));
printf("%d\n",delnum(myq));
printf("%d\n",delnum(myq));
printf("%d\n",delnum(myq));//隊(duì)列空了就返回-1
return 0;
}
PCF就支持C呀!
MQ還提供了系統(tǒng)管理的編程接口,通過(guò)該接口用戶可以編寫應(yīng)用程序從而進(jìn)行自動(dòng)化的實(shí)時(shí)監(jiān)控及管理。MQ的系統(tǒng)管理接口有兩種,即Programmable Command Format(可編程命令格式,簡(jiǎn)稱PCF)和MQ Administration Interface(MQ管理接口,簡(jiǎn)稱MQAI)。
關(guān)于WebSphere MQ 可編程命令格式(PCF)
WebSphere MQ 可編程命令格式(PCF)命令使得管理任務(wù)能編寫到應(yīng)用程序中,在程序中可以創(chuàng)建隊(duì)列、進(jìn)程等對(duì)象的定義以及更改對(duì)象的屬性等。
PCF定義了命令和回復(fù)消息,應(yīng)用程序通過(guò)這些命令和回復(fù)消息實(shí)現(xiàn)和隊(duì)列管理器之間的信息交換,PCF 命令和MQSC 命令具有相同的命令集,所有通過(guò)MQSC命令能夠?qū)崿F(xiàn)的功能,通過(guò)PCF都可以實(shí)現(xiàn),因此,通過(guò)WebSphere MQ的應(yīng)用程序可以實(shí)現(xiàn)對(duì)MQ對(duì)象的管理包括:隊(duì)列管理器,進(jìn)程定義,隊(duì)列和通道等。PCF命令可以被發(fā)送到本地隊(duì)列管理器的命令隊(duì)列,也可以被發(fā)送到某個(gè)遠(yuǎn)程隊(duì)列管理器的命令隊(duì)列,因此,應(yīng)用程序可以通過(guò)一個(gè)本地隊(duì)列管理器集中管理網(wǎng)絡(luò)中的任何本地和遠(yuǎn)程管理器。
MQ的遠(yuǎn)程管理機(jī)制底層就是通過(guò)PCF這種方式的,在互相聯(lián)接的系統(tǒng)中的任意一個(gè)節(jié)點(diǎn)都可以進(jìn)行對(duì)其他所有節(jié)點(diǎn)的配置和管理,這種情形的典型應(yīng)用就是通過(guò)一臺(tái)Windows操作系統(tǒng)的機(jī)器來(lái)管理全網(wǎng)的MQ節(jié)點(diǎn)。由于MQ在Windows XP/NT/2000平臺(tái)上提供了圖形界面的管理工具,我們可以把一個(gè)節(jié)點(diǎn)設(shè)成管理機(jī),利用管理機(jī)可以監(jiān)控和配置網(wǎng)絡(luò)中的任一節(jié)點(diǎn),監(jiān)測(cè)和顯示整個(gè)網(wǎng)絡(luò)中任何一個(gè)節(jié)點(diǎn)上的服務(wù)器及其各種對(duì)象的狀態(tài)和運(yùn)行情況,從而實(shí)現(xiàn)對(duì)中間件的集中管理和監(jiān)控。
每一個(gè)隊(duì)列管理器有一個(gè)名為SYSTEM.ADMIN.COMMAND.QUEUE的管理隊(duì)列,應(yīng)用程序可以按照PCF命令消息格式封裝的要求,組成PCF消息,并將該P(yáng)CF命令消息發(fā)送到管理隊(duì)列中,同時(shí),每一個(gè)隊(duì)列管理器也有一個(gè)命令服務(wù)器(Command Server),它為管理隊(duì)列中的消息提供服務(wù),在我們使用MQ的控制命令strmqcsv啟動(dòng)命令服務(wù)器之后,它將監(jiān)控管理隊(duì)列,一旦該隊(duì)列中有PCF消息到達(dá),它將讀取該消息,并解釋執(zhí)行。因此在網(wǎng)絡(luò)中的任何隊(duì)列管理器都可以處理PCF消息,通過(guò)使用指定的回復(fù)隊(duì)列,回復(fù)消息可以被返回給應(yīng)用程序,應(yīng)用程序可以獲知PCF命令執(zhí)行成功與否。回復(fù)隊(duì)列由命令消息的消息描述符(MQMD)中的ReplyToQ和ReplyToQMgr兩個(gè)字段來(lái)指定。
PCF命令和回復(fù)消息是使用MQ相應(yīng)的編程接口進(jìn)行發(fā)送和接收的,以C語(yǔ)言為例,我們只需要使用MQPUT將PCF命令消息發(fā)送到相應(yīng)的管理隊(duì)列,使用MQGET將PCF回復(fù)消息從相應(yīng)的回復(fù)隊(duì)列中取出即可。這里的關(guān)鍵就是如何封裝PCF消息。每個(gè)MQ指令及其相關(guān)參數(shù)都是一條單獨(dú)的命令消息,每個(gè)命令消息由PCF頭和若干個(gè)參數(shù)結(jié)構(gòu)塊組成,每個(gè)參數(shù)結(jié)構(gòu)塊提供了命令的參數(shù)?;貜?fù)消息的結(jié)構(gòu)與命令消息相同,但是回復(fù)消息的個(gè)數(shù)根據(jù)不同的情況可能會(huì)有多個(gè),例如:如果我們查詢某個(gè)隊(duì)列管理器下所有本地隊(duì)列的屬性,假設(shè)本地隊(duì)列有10個(gè),那么我們將得到10個(gè)回復(fù)消息,PCF頭中的Control字段MQCFC_NOT_LAST和MQCFC_LAST將用于區(qū)分是否為最后一個(gè)回復(fù)消息。
PCF編程接口支持C,Visual Basic, COBOL, RPG, PL/1和Java等,其中在我們最常用的編程語(yǔ)言中,C和Visual Basic編程在PCF的封裝上相對(duì)Java將會(huì)略微復(fù)雜一些
網(wǎng)上貌似大堆啊,如果不合適,可以找我,根據(jù)你的要求定制或移植
int main(void)
{
int max(int x, int y); //加上聲明
int a,b,c; //多定義了沒(méi)用的數(shù)據(jù)
scanf("%d,%d",a,b);
c = max(a,b);
printf("max is %d",c);
}
int max(int x,int y) //加上返回值類型int
{
int z;
if(xy) z=x; //不要逗號(hào)
else z=y;
return z;
}