當前位置:首頁 » 編程軟體 » 規約編譯

規約編譯

發布時間: 2023-03-21 09:02:18

A. 編譯原理,算符優先文法採用"移進-規約"技術,其規約過程是規范的. 這句話錯在哪了謝謝

算符優先文法確實使用了移入歸約技術,但其歸約過程不滿足規范歸約(最左歸約),算符優先文法每次歸約的是最左素短語,而規范歸約每次歸約的是最左直接短語(句柄)

B. 編譯原理怎麼判斷是否為slr文法

LL(1)就是向前只搜索1個符號,即與FIRST()匹配,如果FIRST為空則還要考慮FELLOW.
LR需要構造一張LR分析表,此表用於當面臨輸入字元時,將它移進,規約(即自下而上分析思想),接受還是出錯.
LR(0)找出句柄前綴,構造分析表,然後根據輸入符號進行規約.
SLR(1)使用LR(0)時若有沖突,不知道規約,移進,活移進哪一個,所以需要向前搜索,則只把有問題的地方向前搜索一次.
LR(1)1.在每個項目中增加搜索符.2.舉個列子如有A->α.Bβ,則還需將B的規則也加入.
LALR(1)就是假如兩個產生式集相同則將它們合並為一個,幾合並同心集.

C. 規約的編譯原理

推導的逆過程稱為規約。規約就是選擇一個文法規則:X→ABC,依次從棧頂彈出C、B、A,再將X壓進棧。規范規約是文法中句子的一個最右推導的逆過程,而最左推導對應的是最右規約 。
另外在程序設計中的規約:∏和∏'是兩個判定性問題,如果存在一個確定性演算法A使得對於一個∏的實例I,A可以將I在多項式時間里轉換成∏'的實例P,使得I得到肯定的回答,當且僅當I'得到肯定回答,則稱∏在多項式時間里規約到∏',記為∏∝poly∏'.

D. 編譯原理試題

習題一、單項選擇題
1、將編譯程序分成若干個「遍」是為了 。
a.提高程序的執行效率
b.使程序的結構更加清晰
c.利用有限的機器內存並提高機器的執行效率
d.利用有限的機器內存但降低了機器的執行效率
2、構造編譯程序應掌握 。
a.源程序 b.目標語言
c.編譯方法 d.以上三項都是
3、變數應當 。
a.持有左值 b.持有右值
c.既持有左值又持有右值 d.既不持有左值也不持有右值
4、編譯程序絕大多數時間花在 上。
a.出錯處理 b.詞法分析
c.目標代碼生成 d.管理表格
5、 不可能是目標代碼。
a.匯編指令代碼 b.可重定位指令代碼
c.絕對指令代碼 d.中間代碼
6、使用 可以定義一個程序的意義。
a.語義規則 b.詞法規則
c.產生規則 d.詞法規則
7、詞法分析器的輸入是 。
a.單詞符號串 b.源程序
c.語法單位 d.目標程序
8、中間代碼生成時所遵循的是- 。
a.語法規則 b.詞法規則
c.語義規則 d.等價變換規則
9、編譯程序是對 。
a.匯編程序的翻譯 b.高級語言程序的解釋執行
c.機器語言的執行 d.高級語言的翻譯
10、語法分析應遵循 。
a.語義規則 b.語法規則
c.構詞規則 d.等價變換規則
解答
1、將編譯程序分成若干個「遍」是為了使編譯程序的結構更加清晰,故選b。
2、構造編譯程序應掌握源程序、目標語言及編譯方法等三方面的知識,故選d。
3、對編譯而言,變數既持有左值又持有右值,故選c。
4、編譯程序打交道最多的就是各種表格,因此選d。
5、目標代碼包括匯編指令代碼、可重定位指令代碼和絕對指令代碼3種,因此不是目標代碼的只能選d。
6、詞法分析遵循的是構詞規則,語法分析遵循的是語法規則,中間代碼生成遵循的是語義規則,並且語義規則可以定義一個程序的意義。因此選a。
7、b 8、c 9、d 10、c
二、多項選擇題
1、編譯程序各階段的工作都涉及到 。
a.語法分析 b.表格管理 c.出錯處理
d.語義分析 e.詞法分析
2、編譯程序工作時,通常有 階段。
a.詞法分析 b.語法分析 c.中間代碼生成
d.語義檢查 e.目標代碼生成
解答
1.b、c 2. a、b、c、e
三、填空題
1、解釋程序和編譯程序的區別在於 。
2、編譯過程通常可分為5個階段,分別是 、語法分析 、代碼優化和目標代碼生成。 3、編譯程序工作過程中,第一段輸入是 ,最後階段的輸出為 程序。
4、編譯程序是指將 程序翻譯成 程序的程序。 解答
是否生成目標程序 2、詞法分析 中間代碼生成 3、源程序 目標代碼生成 4、源程序 目標語言
一、單項選擇題
1、文法G:S→xSx|y所識別的語言是 。
a. xyx b. (xyx)* c. xnyxn(n≥0) d. x*yx*
2、文法G描述的語言L(G)是指 。
a. L(G)={α|S+ ⇒α , α∈VT*} b. L(G)={α|S*⇒α, α∈VT*}
c. L(G)={α|S*⇒α,α∈(VT∪VN*)} d. L(G)={α|S+ ⇒α, α∈(VT∪VN*)}
3、有限狀態自動機能識別 。
a. 上下文無關文法 b. 上下文有關文法
c.正規文法 d. 短語文法
4、設G為算符優先文法,G的任意終結符對a、b有以下關系成立 。
a. 若f(a)>g(b),則a>b b.若f(a)<g(b),則a<b
c. a~b都不一定成立 d. a~b一定成立
5、如果文法G是無二義的,則它的任何句子α 。
a. 最左推導和最右推導對應的語法樹必定相同
b. 最左推導和最右推導對應的語法樹可能不同
c. 最左推導和最右推導必定相同
d. 可能存在兩個不同的最左推導,但它們對應的語法樹相同
6、由文法的開始符經0步或多步推導產生的文法符號序列是 。
a. 短語 b.句柄 c. 句型 d. 句子
7、文法G:E→E+T|T
T→T*P|P
P→(E)|I
則句型P+T+i的句柄和最左素短語為 。
a.P+T和i b. P和P+T c. i和P+T+i d.P和T
8、設文法為:S→SA|A
A→a|b
則對句子aba,下面 是規范推導。
a. SÞSAÞSAAÞAAAÞaAAÞabAÞaba
b. SÞSAÞSAAÞAAAÞAAaÞAbaÞaba
c. SÞSAÞSAAÞSAaÞSbaÞAbaÞaba
d. SÞSAÞSaÞSAaÞSbaÞAbaÞaba
9、文法G:S→b|∧(T)
T→T,S|S
則FIRSTVT(T) 。
a. {b,∧,(} b. {b,∧,)} c.{b,∧,(,,} d.{b,∧,),,}
10、產生正規語言的文法為 。
a. 0型 b. 1型 c. 2型 d. 3型
11、採用自上而下分析,必須 。
a. 消除左遞歸 b. 消除右遞歸 c. 消除回溯 d. 提取公共左因子
12、在規范歸約中,用 來刻畫可歸約串。
a. 直接短語 b. 句柄 c. 最左素短語 d. 素短語
13、有文法G:E→E*T|T
T→T+i|i
句子1+2*8+6按該文法G歸約,其值為 。
a. 23 B. 42 c. 30 d. 17
14、規范歸約指 。
a. 最左推導的逆過程 b. 最右推導的逆過程
c. 規范推導 d. 最左歸約的逆過程
[解答]
1、選c。
2、選a。
3、選c。
4、雖然a與b沒有優先關系,但構造優先函數後,a與b就一定存在優先關系了。所以,由f(a)>g)(b)或f(a)<g(b)並不能判定原來的a與b之間是否存在優先關系:故選c。
5、如果文法G無二義性,則最左推導是先生長右邊的枝葉:對於d,如果有兩個不同的是了左推導,則必然有二義性。故選a。
6、選c。
7、由圖2-8-1的語法樹和優先關系可以看出應選b。

8、規范推導是最左推導,故選d。
9、由T→T,…和T→(… 得FIRSTVT(T))={(,,)};
由T→S得FIRSTVT(S)⊂FIRSTVT(T),而FIRSTVT(S)={b,∧,(};即
FIRSTVT(T)={b,∧,(,,}; 因此選c。
10、d 11、c 12、b 13、b 14、b
二、多項選擇題
1、下面哪些說法是錯誤的 。
a. 有向圖是一個狀態轉換圖 b. 狀態轉換圖是一個有向圖
c.有向圖是一個DFA d.DFA可以用狀態轉換圖表示
2、對無二義性文法來說,一棵語法樹往往代表了 。
a. 多種推導過程 b. 多種最左推導過程 c.一種最左推導過程
d.僅一種推導過程 e.一種最左推導過程
3、如果文法G存在一個句子,滿足下列條件 之一時,則稱該文法是二義文法。
a. 該句子的最左推導與最右推導相同
b. 該句子有兩個不同的最左推導
c. 該句子有兩棵不同的最右推導
d. 該句子有兩棵不同的語法樹
e.該句子的語法樹只有一個
4、有一文法G:S→AB
A→aAb|ε
B→cBd|ε
它不產生下面 集合。
a. {anbmcndm|n,m≥0} b. {anbncmdm|n,m>0}
c. {anbmcmdn|n,m≥0} d. {anbncmdm|n,m≥0}
e. {anbncndn|n≥0}
5、自下而上的語法分析中,應從 開始分析。
a. 句型 b. 句子 c. 以單詞為單位的程序
d. 文法的開始符 e. 句柄
6、對正規文法描述的語言,以下 有能力描述它。
a.0型文法 b.1型文法 c.上下文無關文法 d.右線性文法 e.左線性文法
解答 1、e、a、c 2、a、c、e 3、b、c、d 4、a、c 5、b、c 6、a、b、c、d、e
三、填空題
1、文法中的終結符和非終結符的交集是 。詞法分析器交給語法分析器的文法符號一定是 ,它一定只出現在產生式的 部。
2、最左推導是指每次都對句型中的 非終結符進行擴展。
3、在語法分析中,最常見的兩種方法一定是 分析法,另一是 分析法。
4、採用 語法分析時,必須消除文法的左遞歸。
5、 樹代表推導過程, 樹代表歸約過程。
6、自下而上分析法採用 、歸約、錯誤處理、 等四種操作。
7、Chomsky把文法分為 種類型,編譯器構造中採用 和 文法,它們分別產生 和 語言,並分別用 和 自動機識別所產生的語言。
解答 1、空集 終結符 右
2、最左
3、自上而上 自下而上
4、自上而上
5、語法 分析
6、移進 接受
7、4 2 型 3型 上下文無關語言 正規語言 下推自動機 有限
四、判斷題
1、文法 S→aS|bR|ε描述的語言是(a|bc)* ( )
R→cS
2、在自下而上的語法分析中,語法樹與分析樹一定相同。 ( )
3、二義文法不是上下文無關文法。 ( )
4、語法分析時必須先消除文法中的左遞歸。 ( )
5、規范歸約和規范推導是互逆的兩個過程。 ( )
6、一個文法所有句型的集合形成該文法所能接受的語言。 ( )
解答 1、對 2、錯 3、錯 4、錯 5、錯 6、錯
五、簡答題
1、句柄 2、素短語 3、語法樹 4、歸約 5、推導
[解答]
1、句柄:一個句型的最左直接短語稱為該句型的句柄。
2、素短語:至少含有一個終結符的素短語,並且除它自身之外不再含任何更小的素短語。
3、語法樹:滿足下面4個條件的樹稱之為文法G[S]的一棵語法樹。
①每一終結均有一標記,此標記為VN∪VT中的一個符號;
②樹的根結點以文法G[S]的開始符S標記;
③若一結點至少有一個直接後繼,則此結點上的標記為VN中的一個符號;
④若一個以A為標記的結點有K個直接後繼,且按從左至右的順序,這些結點的標記分別為X1,X2,…,XK,則A→X1,X2,…,XK,必然是G的一個產生式。
4、歸約:我們稱αγβ直接歸約出αAβ,僅當A→γ 是一個產生式,且α、β∈(VN∪VT)*。歸約過程就是從輸入串開始,反復用產生式右部的符號替換成產生式左部符號,直至文法開始符。
5、推導:我們稱αAβ直接推出αγβ,即αAβÞαγβ,僅當A→ γ 是一個產生式,且α、β∈(VN∪VT)*。如果α1Þα2Þ…Þαn,則我們稱這個序列是從α1至α2的一個推導。若存在一個從α1αn的推導,則稱α1可推導出αn。推導是歸約的逆過程。
六、問答題
1、給出上下文無關文法的定義。
[解答]
一個上下文無關文法G是一個四元式(VT,VN,S, P),其中:
●VT是一個非空有限集,它的每個元素稱為終結符號;
●VN是一個非空有限集,它的每個元素稱為非終結符號,VT∩VN=Φ;
●S是一個非終結符號,稱為開始符號;
●P是一個產生式集合(有限),每個產生式的形式是P→α,其中,P∈VN,
α∈(VT∪VN)*。開始符號S至少必須在某個產生式的左部出現一次。
2、文法G[S]:
S→aSPQ|abQ
QP→PQ
bP→bb
bQ→bc
cQ→cc
(1)它是Chomsky哪一型文法?
(2)它生成的語言是什麼?
[解答]
(1)由於產生式左部存在終結符號,且所有產生式左部符號的長度均小於等於產生式右部的符號長度,所以文法G[S]是Chomsky1型文法,即上下文有關文法。
(2)按產生式出現的順序規定優先順序由高到低(否則無法推出句子),我們可以得到:
SÞabQÞabc
SÞaSPQÞaabQPQÞaabPQQÞaabbQQÞaabbcQÞaabbcc
SÞaSPQÞaaSPQPQÞaaabQPQPQÞaaabPQQPQÞaaabPQPQQÞaaaPPQQQÞ
aaabbPqqqÞaaabbQQQÞaaabbbcQQÞaaabbbccQÞaaabbbccc
……
於是得到文法G[S]生成的語言L={anbncn|n≥1}
3、按指定類型,給出語言的文法。
L={aibj|j>i≥1}的上下文無關文法。
【解答】
(1)由L={aibj|j>i≥1}知,所求該語言對應的上下文無關文法首先應有S→aSb型產生式,以保證b的個數不少於a的個數;其次,還需有S→Sb或S→bS型的產生式,用以保證b的個數多於a的個數;也即所求上下文無關文法G[S]為:
G[S]:S→aSb|Sb|b
4、有文法G:S→aAcB|Bd
A→AaB|c
B→bScA|b
(1)試求句型aAaBcbbdcc和aAcbBdcc的句柄;
(2)寫出句子acabcbbdcc的最左推導過程。
【解答】(1)分別畫出對應兩句型的語法樹,如圖2-8-2所示
句柄:AaB Bd

圖2-8-2 語法樹
(2)句子acabcbbdcc的最左推導如下:
SÞaAcBÞaAaBcBÞacaBcBÞacabcBÞacabcbScAÞacabcbBdcA
ÞacabcbbdcAÞacabcbbdcc
5、對於文法G[S]:
S→(L)|aS|a L→L, S|S
(1)畫出句型(S,(a))的語法樹。(2)寫出上述句型的所有短語、直接短語、句柄和素短語。
【解答】
(1)句型(S,(a))的語法樹如圖2-8-3所示

(2)由圖2-8-3可知:
①短語:S、a、(a)、S,(a)、(S,(a));
②直接短語:a、S;
③句柄:S;
④素短語:素短語可由圖2-8-3中相鄰終結符之間的優先關系求得,即;

因此素短語為a。
6、考慮文法G[T]:
T→T*F|F
F→F↑P|P
P→(T)|i
證明T*P↑(T*F)是該文法的一個句型,並指出直接短語和句柄。
【解答】
首先構造T*P↑(T*F)的語法樹如圖2-8-4所示。

由圖2-8-4可知,T*P↑(T*F)是文法G[T]的一個句型。
直接短語有兩個,即P和T*F;句柄為P。

一、單項選擇題
1、詞法分析所依據的是 。
a. 語義規則 b. 構詞規則 c. 語法規則 d. 等價變換規則
2、詞法分析器的輸出結果是 。
a. 單詞的種別編碼 b. 單詞在符號表中的位置
c. 單詞的種別編碼和自身值 d. 單詞自身值
3、正規式M1和M2等價是指 。
a. M1和M2的狀態數相等 b. M1和M2的有向弧條數相等
c. M1和M2所識別的語言集相等 d. M1和M2狀態數和有向弧條數相等
4、狀態轉換圖(見圖3-6-1)接受的字集為 。

a. 以 0開頭的二進制數組成的集合 b. 以0結尾的二進制數組成的集合
c. 含奇數個0的二進制數組成的集合 d. 含偶數個0的二進制數組成的集合
5、詞法分析器作為獨立的階段使整個編譯程序結構更加簡潔、明確,因此, 。
a. 詞法分析器應作為獨立的一遍 b. 詞法分析器作為子程序較好
c. 詞法分析器分解為多個過程,由語法分析器選擇使用 d. 詞法分析器並不作為一個獨立的階段
解答 1、b 2、c 3、c 4、d 5、b
二、多項選擇題
1、在詞法分析中,能識別出 。
a. 基本字 b. 四元式 c. 運算符
d. 逆波蘭式 e. 常數
2、令∑={a,b},則∑上所有以b開頭,後跟若干個ab的字的全體對應的正規式為 。
a. b(ab)* b. b(ab)+ c.(ba)*b
d. (ba)+b e. b(a|b)
解答 1、a、c、e 2、a、b、d
三、填空題
1、確定有限自動機DFA是 的一個特例。
2、若二個正規式所表示的 相同,則認為二者是等價的。
3、一個字集是正規的,當且僅當它可由 所 。
解答 1、NFA 2、正規集 3、DFA(NFA)所識別
四、判斷題
1、一個有限狀態自動機中,有且僅有一個唯一終態。 ( )
2、設r和s分別是正規式,則有L(r|s)=L(r)|L(s)。 ( )
3、自動機M和M′的狀態數不同,則二者必不等價。 ( )
4、確定的自動機以及不確定的自動機都能正確地識別正規集。 ( )
5、對任意一個右線性文法G,都存在一個NFA M,滿足L(G)=L(M)。 ( )
6、對任意一個右線性文法G,都存在一個DFA M,滿足L(G)=L(M)。 ( )
7、對任何正規表達式e,都存在一個NFA M,滿足L(G)=L(e)。 ( )
8、對任何正規表達式e,都存在一個DFA M,滿足L(G)=L(e)。 ( )
解答 1 、2、3、錯 4、5、6、7、8、正確
五、基本題
1、設M=({x,y}, {a,b}, f,x,{y})為一非確定的有限自動機,其中f定義如下:
f(x,a)={x,y} f(x,b)={y}
f(y,a)=φ f(y,b)={x,y}
試構造相應的確定有限自動機M′。
解答:對照自動機的定義M=(S,Σ,f,S0,Z),由f的定義可知f(x,a)、f(y,b)均為多值函數,所以是一非確定有限自動機,先畫出NFA M相應的狀態圖,如圖3-6-2所示。

用子集法構造狀態轉換矩陣表3-6-3所示。
I Ia Ib
{x} {x,y} {y}
{y} — {x,y}
{x,y} {x,y} {x,y}
將轉換矩陣中的所有子集重新命名而形成表3-6-4所示的狀態轉換矩陣。
表3-6-4 狀態轉換矩陣
a b
0 2 1
1 — 2
2 2 2
即得到M′=({0,1,2}, {a,b}, f,0, {1,2}),其狀態轉換圖如圖3-6-5所示。

將圖3-6-5的DFA M′最小化。首先,將M′的狀態分成終態組{1,2}與非終態組{0};其次,考察{1,2}。由於{1,2}a={1,2}b={2}⊂{1,2},所以不再將其劃分了,也即整個劃分只有兩組{0},{1,2}:令狀態1代表{1,2},即把原來到達2的弧都導向1,並刪除狀態2。最後,得到如圖3-6-6所示化簡DFA M′。

2、對給定正規式b*(d|ad)(b|ab)+,構造其NFA M;
解答:首先用A+=AA*改造正規式得:b*(d|ad)(b|ab)(b|ab)*;其次,構造該正規式的NFA M,如圖3-6-7所示。

E. 請問規范規約是什麼意思(這個詞應該是用在計算機編譯原理中)

在編譯原理中,規范規約是編譯程序中語法分析(自下而上分析)階段的,在此階段中處理文法和句子。規范規約是文法中句子的一個最右推導的逆過程。
如果你是沒學過編譯原理的,這個具體要說意思的話,太抽象。你只要知道編譯程序的工作是從輸入源程序開始到輸出目標程序為止的整個過程,而這個過程可分為五個階段:詞法分析、語法分析、語義分析與中間代碼產生、優化、目標代碼生成。規范規約就是語法分析中用到的,為後面的步驟做准備。

F. 編譯原理簡單文法歸約計算

編譯原理中的語法和文法是不一樣的,但卻融會貫通。
在計算機科學中,文法是編譯原理的基礎,是描述一門程序設計語言和實現其編譯器的方法。
文法分成四種類型,即0型、1型、2型和3型。這幾類文法的差別在於對產生式施加不同的限制。
形式語言,這種理論對計算機科學有著深刻的影響,特別是對程序設計語言的設計、編譯方法和計算復雜性等方面更有重大的作用。
多數程序設計語言的單詞的語法都能用正規文法或3型文法(3型文法G=(VN,VT,P,S)的P中的規則有兩種形式:一種是前面定義的形式,即:A→aB或A→a其中A,B∈VN ,a∈VT*,另一種形式是:A→Ba或A→a,前者稱為右線性文法,後者稱為左線性文法。正規文法所描述的是VT*上的正規集)來描述。
四個文法類的定義是逐漸增加限制的,因此每一種正規文法都是上下文無關的,每一種上下文無關文法都是上下文有關的,而每一種上下文有關文法都是0型文法。稱0型文法產生的語言為0型語言。上下文有關文法、上下文無關文法和正規文法產生的語言分別稱為上下文有關語言、上下文無關語言和正規語言。

G. jdk內有哪些約定俗成的命名規則和規范

2017版的阿里java開發手冊:比較多,只能復制一部分,你可以去網路具體的

一、編程規約
(一)命名規約
1.【強制】代碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。
反例:_name/__name/$Object/name_/name$/Object$
2.【強制】代碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。
說明:正確的英文拼寫和語法可以讓閱讀者易於理解,避免歧義。注意,即使純拼音命名方式
也要避免採用。
反例:DaZhePromotion[打折]/getPingfenByName()[評分]/int某變數=3
正例:alibaba/taobao/youku/hangzhou等國際通用的名稱,可視同英文。
3.【強制】類名使用UpperCamelCase風格,必須遵從駝峰形式,但以下情形例外:(領域模型
的相關命名)DO/BO/DTO/VO等。
正例:MarcoPolo/UserDO/XmlService/TcpUdpDeal/TaPromotion
反例:macroPolo/UserDo/XMLService/TCPUDPDeal/TAPromotion
4.【強制】方法名、參數名、成員變數、局部變數都統一使用lowerCamelCase風格,必須遵從
駝峰形式。
正例:localValue/getHttpMessage()/inputUserId
5.【強制】常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長。
正例:MAX_STOCK_COUNT
反例:MAX_COUNT
6.【強制】抽象類命名使用Abstract或Base開頭;異常類命名使用Exception結尾;測試類
命名以它要測試的類的名稱開始,以Test結尾。
7.【強制】中括弧是數組類型的一部分,數組定義如下:String[]args;
反例:使用Stringargs[]的方式來定義。
8.【強制】POJO類中布爾類型的變數,都不要加is,否則部分框架解析會引起序列化錯誤。
反例:定義為基本數據類型BooleanisSuccess;的屬性,它的方法也是isSuccess(),RPC
框架在反向解析的時候,「以為」對應的屬性名稱是success,導致屬性獲取不到,進而拋出異
常。
9.【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用
單數形式,但是類名如果有復數含義,類名可以使用復數形式。
正例:應用工具類包名為com.alibaba.open.util、類名為MessageUtils(此規則參考
spring的框架結構)
10.【強制】杜絕完全不規范的縮寫,避兆鉛棗免望文不知義。
反例:AbstractClass「縮寫」命名成AbsClass;condition「縮寫」命名成condi,此類
隨意縮寫嚴重降低了代碼的可閱讀激陪性。
11.【推薦】如果使用到了設計模式,建議在類名中體現出具體模式。
說明:將設計模式體現在名字中,有利於閱讀者快速理解架構設計思想。
正例:publicclassOrderFactory;
publicclassLoginProxy;
publicclassResourceObserver;
12.【推薦】介面類中的方法和屬性不要加任何修飾符號(public也不要加),保持代碼的簡潔
性,並加上有效的Javadoc注釋。盡量不要在介面里定義變數,如果一定要定義變數,肯定是
與介面方法相關,並且是整個應用的基礎常量。
正例:介面方法簽名:voidf();
介面基礎常量表示:StringCOMPANY="alibaba";
反例:介面方法定義:publicabstractvoidf();
說明:JDK8中介面允許有默認實現,那麼這個default方法,是對所有實現類都有價值的默
認實現。
13.介面和實現類的命名有兩套規則:
1)【強制】對於Service和DAO類,基於SOA的理念,暴露出來的服務一定是介面,內部
的實現類用Impl的後綴與介面區別。
正例:CacheServiceImpl實現CacheService介面。
2)【推薦】如果是形容能力的介面名稱,取對應的形容詞做介面名(通常是–able的形式)。
正例:AbstractTranslator實現Translatable。
14.【參考】枚舉類名建議帶上Enum後族拆綴,枚舉成員名稱需要全大寫,單詞間用下劃線隔開。
說明:枚舉其實就是特殊的常量類,且構造方法被默認強制是私有。
正例:枚舉名字:DealStatusEnum,成員名稱:SUCCESS/UNKOWN_REASON。
15.【參考】各層命名規約:
A)Service/DAO層方法命名規約
1)獲取單個對象的方法用get做前綴。
2)獲取多個對象的方法用list做前綴。
3)獲取統計值的方法用count做前綴。
4)插入的方法用save(推薦)或insert做前綴。
5)刪除的方法用remove(推薦)或delete做前綴。
6)修改的方法用update做前綴。
B)領域模型命名規約
1)數據對象:xxxDO,xxx即為數據表名。
2)數據傳輸對象:xxxDTO,xxx為業務領域相關的名稱。
3)展示對象:xxxVO,xxx一般為網頁名稱。
4)POJO是DO/DTO/BO/VO的統稱,禁止命名成xxxPOJO。
(二)常量定義
1.【強制】不允許出現任何魔法值(即未經定義的常量)直接出現在代碼中。
反例:Stringkey="Id#taobao_"+tradeId;
cache.put(key,value);
2.【強制】long或者Long初始賦值時,必須使用大寫的L,不能是小寫的l,小寫容易跟數字
1混淆,造成誤解。
說明:Longa=2l;寫的是數字的21,還是Long型的2?
3.【推薦】不要使用一個常量類維護所有常量,應該按常量功能進行歸類,分開維護。如:緩存
相關的常量放在類:CacheConsts下;系統配置相關的常量放在類:ConfigConsts下。
說明:大而全的常量類,非得使用查找功能才能定位到修改的常量,不利於理解和維護。
4.【推薦】常量的復用層次有五層:跨應用共享常量、應用內共享常量、子工程內共享常量、包
內共享常量、類內共享常量。
1)跨應用共享常量:放置在二方庫中,通常是client.jar中的constant目錄下。
2)應用內共享常量:放置在一方庫的moles中的constant目錄下。
反例:易懂變數也要統一定義成應用內共享常量,兩位攻城師在兩個類中分別定義了表示
「是」的變數:
類A中:publicstaticfinalStringYES="yes";
類B中:publicstaticfinalStringYES="y";
A.YES.equals(B.YES),預期是true,但實際返回為false,導致產生線上問題。
3)子工程內部共享常量:即在當前子工程的constant目錄下。
4)包內共享常量:即在當前包下單獨的constant目錄下。
5)類內共享常量:直接在類內部privatestaticfinal定義。
5.【推薦】如果變數值僅在一個范圍內變化用Enum類。如果還帶有名稱之外的延伸屬性,必須
使用Enum類,下面正例中的數字就是延伸信息,表示星期幾。
正例:publicEnum{MONDAY(1),TUESDAY(2),WEDNESDAY(3),THURSDAY(4),FRIDAY(5),SATURDAY(6),
SUNDAY(7);}
(三)格式規約
1.【強制】大括弧的使用約定。如果是大括弧內為空,則簡潔地寫成{}即可,不需要換行;如果
是非空代碼塊則:
1)左大括弧前不換行。
2)左大括弧後換行。
3)右大括弧前換行。
4)右大括弧後還有else等代碼則不換行;表示終止右大括弧後必須換行。
2.【強制】左括弧和後一個字元之間不出現空格;同樣,右括弧和前一個字元之間也不出現空
格。詳見第5條下方正例提示。
3.【強制】if/for/while/switch/do等保留字與左右括弧之間都必須加空格。
4.【強制】任何運算符左右必須加一個空格。
說明:運算符包括賦值運算符=、邏輯運算符&&、加減乘除符號、三目運算符等。
5.【強制】縮進採用4個空格,禁止使用tab字元。
說明:如果使用tab縮進,必須設置1個tab為4個空格。IDEA設置tab為4個空格時,
請勿勾選Usetabcharacter;而在eclipse中,必須勾選insertspacesfortabs。
正例:(涉及1-5點)
publicstaticvoidmain(String[]args){
//縮進4個空格
Stringsay="hello";
//運算符的左右必須有一個空格
intflag=0;
//關鍵詞if與括弧之間必須有一個空格,括弧內的f與左括弧,0與右括弧不需要空格
if(flag==0){
System.out.println(say);
}

//左大括弧前加空格且不換行;左大括弧後換行
if(flag==1){
System.out.println("world");
//右大括弧前換行,右大括弧後有else,不用換行
阿里巴巴Java開發手冊
——禁止用於商業用途,違者必究——6/37

}else{
System.out.println("ok");
//在右大括弧後直接結束,則必須換行
}
}
6.【強制】單行字元數限制不超過120個,超出需要換行,換行時遵循如下原則:
1)第二行相對第一行縮進4個空格,從第三行開始,不再繼續縮進,參考示例。
2)運算符與下文一起換行。
3)方法調用的點符號與下文一起換行。
4)在多個參數超長,逗號後進行換行。
5)在括弧前不要換行,見反例。
正例:
StringBuffersb=newStringBuffer();
//超過120個字元的情況下,換行縮進4個空格,並且方法前的點符號一起換行
sb.append("zi").append("xin")...
.append("huang")...
.append("huang")...
.append("huang");
反例:
StringBuffersb=newStringBuffer();
//超過120個字元的情況下,不要在括弧前換行
sb.append("zi").append("xin")...append
("huang");

//參數很多的方法調用可能超過120個字元,不要在逗號前換行
method(args1,args2,args3,...
,argsX);
7.【強制】方法參數在定義和傳入時,多個參數逗號後邊必須加空格。
正例:下例中實參的"a",後邊必須要有一個空格。
method("a","b","c");
8.【強制】IDE的textfileencoding設置為UTF-8;IDE中文件的換行符使用Unix格式,
不要使用windows格式。
9.【推薦】沒有必要增加若干空格來使某一行的字元與上一行的相應字元對齊。
正例:
inta=3;
longb=4L;
floatc=5F;
StringBuffersb=newStringBuffer();
說明:增加sb這個變數,如果需要對齊,則給a、b、c都要增加幾個空格,在變數比較多的
情況下,是一種累贅的事情。
阿里巴巴Java開發手冊
——禁止用於商業用途,違者必究——7/37

10.【推薦】方法體內的執行語句組、變數的定義語句組、不同的業務邏輯之間或者不同的語義
之間插入一個空行。相同業務邏輯和語義之間不需要插入空行。
說明:沒有必要插入多行空格進行隔開。
(四)OOP規約
1.【強制】避免通過一個類的對象引用訪問此類的靜態變數或靜態方法,無謂增加編譯器解析成
本,直接用類名來訪問即可。
2.【強制】所有的覆寫方法,必須加@Override註解。
反例:getObject()與get0bject()的問題。一個是字母的O,一個是數字的0,加@Override
可以准確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進行修改,其實現類會馬上編
譯報錯。
3.【強制】相同參數類型,相同業務含義,才可以使用Java的可變參數,避免使用Object。
說明:可變參數必須放置在參數列表的最後。(提倡同學們盡量不用可變參數編程)
正例:publicUsergetUsers(Stringtype,Integer...ids)
4.【強制】外部正在調用或者二方庫依賴的介面,不允許修改方法簽名,避免對介面調用方產生
影響。介面過時必須加@Deprecated註解,並清晰地說明採用的新介面或者新服務是什麼。
5.【強制】不能使用過時的類或方法。
說明:java.net.URLDecoder中的方法decode(StringencodeStr)這個方法已經過時,應
該使用雙參數decode(Stringsource,Stringencode)。介面提供方既然明確是過時介面,
那麼有義務同時提供新的介面;作為調用方來說,有義務去考證過時方法的新實現是什麼。
6.【強制】Object的equals方法容易拋空指針異常,應使用常量或確定有值的對象來調用
equals。
正例:"test".equals(object);
反例:object.equals("test");
說明:推薦使用java.util.Objects#equals(JDK7引入的工具類)
7.【強制】所有的相同類型的包裝類對象之間值的比較,全部使用equals方法比較。
說明:對於Integervar=?在-128至127之間的賦值,Integer對象是在
IntegerCache.cache產生,會復用已有對象,這個區間內的Integer值可以直接使用==進行
判斷,但是這個區間之外的所有數據,都會在堆上產生,並不會復用已有對象,這是一個大坑,
推薦使用equals方法進行判斷。
8.關於基本數據類型與包裝數據類型的使用標准如下:
1)【強制】所有的POJO類屬性必須使用包裝數據類型。
2)【強制】RPC方法的返回值和參數必須使用包裝數據類型。
3)【推薦】所有的局部變數使用基本數據類型。
說明:POJO類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行賦值,任何
NPE問題,或者入庫檢查,都由使用者來保證。
正例:資料庫的查詢結果可能是null,因為自動拆箱,用基本數據類型接收有NPE風險。
反例:比如顯示成交總額漲跌情況,即正負x%,x為基本數據類型,調用的RPC服務,調用
不成功時,返回的是默認值,頁面顯示:0%,這是不合理的,應該顯示成中劃線-。所以包裝
數據類型的null值,能夠表示額外的信息,如:遠程調用失敗,異常退出。
9.【強制】定義DO/DTO/VO等POJO類時,不要設定任何屬性默認值。
反例:POJO類的gmtCreate默認值為newDate();但是這個屬性在數據提取時並沒有置入具
體值,在更新其它欄位時又附帶更新了此欄位,導致創建時間被修改成當前時間。
10.【強制】序列化類新增屬性時,請不要修改serialVersionUID欄位,避免反序列失敗;如
果完全不兼容升級,避免反序列化混亂,那麼請修改serialVersionUID值。
說明:注意serialVersionUID不一致會拋出序列化運行時異常。
11.【強制】構造方法裡面禁止加入任何業務邏輯,如果有初始化邏輯,請放在init方法中。
12.【強制】POJO類必須寫toString方法。使用IDE的中工具:source>generatetoString
時,如果繼承了另一個POJO類,注意在前面加一下super.toString。
說明:在方法執行拋出異常時,可以直接調用POJO的toString()方法列印其屬性值,便於排
查問題。
13.【推薦】使用索引訪問用String的split方法得到的數組時,需做最後一個分隔符後有無
內容的檢查,否則會有拋IndexOutOfBoundsException的風險。
說明:
Stringstr="a,b,c,,";
String[]ary=str.split(",");
//預期大於3,結果是3
System.out.println(ary.length);
14.【推薦】當一個類有多個構造方法,或者多個同名方法,這些方法應該按順序放置在一起,
便於閱讀。
15.【推薦】類內方法定義順序依次是:公有方法或保護方法>私有方法>getter/setter
方法。
說明:公有方法是類的調用者和維護者最關心的方法,首屏展示最好;保護方法雖然只是子類
關心,也可能是「模板設計模式」下的核心方法;而私有方法外部一般不需要特別關心,是一個
黑盒實現;因為方法信息價值較低,所有Service和DAO的getter/setter方法放在類體最
後。
16.【推薦】setter方法中,參數名稱與類成員變數名稱一致,this.成員名=參數名。在
getter/setter方法中,盡量不要增加業務邏輯,增加排查問題的難度。
反例:
publicIntegergetData(){
if(true){
returndata+100;
}else{
returndata-100;
}
}
17.【推薦】循環體內,字元串的連接方式,使用StringBuilder的append方法進行擴展。
反例:
Stringstr="start";
for(intI=0;I<100;i++){
str=str+"hello";
}
說明:反編譯出的位元組碼文件顯示每次循環都會new出一個StringBuilder對象,然後進行
append操作,最後通過toString方法返回String對象,造成內存資源浪費。
18.【推薦】下列情況,聲明成final會更有提示性:
1)不需要重新賦值的變數,包括類屬性、局部變數。
2)對象參數前加final,表示不允許修改引用的指向。
3)類方法確定不允許被重寫。
19.【推薦】慎用Object的clone方法來拷貝對象。
說明:對象的clone方法默認是淺拷貝,若想實現深拷貝需要重寫clone方法實現屬性對象
的拷貝。
20.【推薦】類成員與方法訪問控制從嚴:
1)如果不允許外部直接通過new來創建對象,那麼構造方法必須是private。
2)工具類不允許有public或default構造方法。
3)類非static成員變數並且與子類共享,必須是protected。
4)類非static成員變數並且僅在本類使用,必須是private。
5)類static成員變數如果僅在本類使用,必須是private。
6)若是static成員變數,必須考慮是否為final。
7)類成員方法只供類內部調用,必須是private。
8)類成員方法只對繼承類公開,那麼限制為protected。
說明:任何類、方法、參數、變數,嚴控訪問范圍。過寬泛的訪問范圍,不利於模塊解耦。思
考:如果是一個private的方法,想刪除就刪除,可是一個public的Service方法,或者一
個public的成員變數,刪除一下,不得手心冒點汗嗎?變數像自己的小孩,盡量在自己的視
線內,變數作用域太大,如果無限制的到處跑,那麼你會擔心的。

H. C和C++如何混合編程

在用C++的項目源碼中,經常會不可避免的會看到下面的代碼:

1
#ifdef __cplusplus

2
extern "C" {

3
#endif

4

5
/*...*/

6

7
#ifdef __cplusplus

8
}

9
#endif

它到底有什麼用呢,你知道嗎?而且這樣的問題經常會出現在面試or筆試中。下面我就從以下幾個方面來介紹它:

1、#ifdef _cplusplus/#endif _cplusplus及發散
2、extern "C"
2.1、extern關鍵字
2.2、"C"
2.3、小結extern "C"
3、C和C++互相調用 4、C和C++混合調用特別之處函數指針
3.1、C++的編譯和連接
3.2、C的編譯和連接
3.3、C++中調用C的代碼
3.4、C中調用C++的代碼

1、#ifdef _cplusplus/#endif _cplusplus及發散

在介紹extern "C"之前,我們來看下#ifdef
_cplusplus/#endif
_cplusplus的作用。很明顯#ifdef/#endif、#ifndef/#endif用於條件編譯,#ifdef
_cplusplus/#endif
_cplusplus——表示如果定義了宏_cplusplus,就執行#ifdef/#endif之間的語句,否則就不執行。

在這里為什麼需要#ifdef _cplusplus/#endif
_cplusplus呢?因為C語言中不支持extern "C"聲明,如果你明白extern
"C"的作用就知道在C中也沒有必要這樣做,這就是條件編譯的作用!在.c文件中包含了extern "C"時會出現編譯時錯誤。

既然說到了條件編譯,我就介紹它的一個重要應用——避免重復包含頭文件。還記得騰訊筆試就考過這個題目,給出類似下面的代碼(下面是我最近在研究的一個開源web伺服器——Mongoose的頭文件mongoose.h中的一段代碼):

01
#ifndef MONGOOSE_HEADER_INCLUDED

02
#define MONGOOSE_HEADER_INCLUDED

03

04
#ifdef __cplusplus

05
extern "C" {

06
#endif /* __cplusplus */

07

08
/*.................................

09
* do something here

10
*.................................

11
*/

12

13
#ifdef __cplusplus

14
}

15
#endif /* __cplusplus */

16

17
#endif /* MONGOOSE_HEADER_INCLUDED */

然後叫你說明上面宏#ifndef/#endif的作用?為了解釋一個問題,我們先來看兩個事實:

這個頭文件mongoose.h可能在項目中被多個源文件包含(#include

"mongoose.h"),而對於一個大型項目來說,這些冗餘可能導致錯誤,因為一個頭文件包含類定義或inline函數,在一個源文件中mongoose.h可能會被#include兩次(如,a.h頭文件包含了mongoose.h,而在b.c文件中#include
a.h和mongoose.h)——這就會出錯(在同一個源文件中一個結構體、類等被定義了兩次)。
從邏輯觀點和減少編譯時間上,都要求去除這些冗餘。然而讓程序員去分析和去掉這些冗餘,不僅枯燥且不太實際,最重要的是有時候又需要這種冗餘來保證各個模塊的獨立。

為了解決這個問題,上面代碼中的

#ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED
/*……………………………*/
#endif /* MONGOOSE_HEADER_INCLUDED */

就起作用了。如果定義了MONGOOSE_HEADER_INCLUDED,#ifndef/#endif之間的內容就被忽略掉。因此,編譯時第一次看到mongoose.h頭文件,它的內容會被讀取且給定MONGOOSE_HEADER_INCLUDED一個值。之後再次看到mongoose.h頭文件時,MONGOOSE_HEADER_INCLUDED就已經定義了,mongoose.h的內容就不會再次被讀取了。

2、extern "C"

首先從字面上分析extern "C",它由兩部分組成——extern關鍵字、"C"。下面我就從這兩個方面來解讀extern "C"的含義。

2.1、extern關鍵字

在一個項目中必須保證函數、變數、枚舉等在所有的源文件中保持一致,除非你指定定義為局部的。首先來一個例子:

1
//file1.c:

2
int x=1;

3
int f(){do something here}

4
//file2.c:

5
extern int x;

6
int f();

7
void g(){x=f();}

在file2.c中g()使用的x和f()是定義在file1.c中的。extern關鍵字表明file2.c中x,僅僅是一個變數的聲明,其並不是在定義變數x,並未為x分配內存空間。變數x在所有模塊中作為一種全局變數只能被定義一次,否則會出現連接錯誤。但是可以聲明多次,且聲明必須保證類型一致,如:

1
//file1.c:

2
int x=1;

3
int b=1;

4
extern c;

5
//file2.c:

6
int x;// x equals to default of int type 0

7
int f();

8
extern double b;

9
extern int c;

在這段代碼中存在著這樣的三個錯誤:

x被定義了兩次
b兩次被聲明為不同的類型
c被聲明了兩次,但卻沒有定義

回到extern關鍵字,extern是C/C++語言中表明函數和全局變數作用范圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變數可以在本模塊或其它模塊中使用。通常,在模塊的頭文件中對本模塊提供給其它模塊引用的函數和全局變數以關鍵字extern聲明。例如,如果模塊B欲引用該模塊A中定義的全局變數和函數時只需包含模塊A的頭文件即可。這樣,模塊B中調用模塊A中的函數時,在編譯階段,模塊B雖然找不到該函數,但是並不會報錯;它會在連接階段中從模塊A編譯生成的目標代碼中找到此函數。

與extern對應的關鍵字是 static,被它修飾的全局變數和函數只能在本模塊中使用。因此,一個函數或變數只可能被本模塊使用時,其不可能被extern 「C」修飾。

2.2、"C"

典型的,一個C++程序包含其它語言編寫的部分代碼。類似的,C++編寫的代碼片段可能被使用在其它語言編寫的代碼中。不同語言編寫的代碼互相調用是困難的,甚至是同一種編寫的代碼但不同的編譯器編譯的代碼。例如,不同語言和同種語言的不同實現可能會在注冊變數保持參數和參數在棧上的布局,這個方面不一樣。

為了使它們遵守統一規則,可以使用extern指定一個編譯和連接規約。例如,聲明C和C++標准庫函數strcyp(),並指定它應該根據C的編譯和連接規約來鏈接:

1
extern "C" char* strcpy(char*,const char*);

注意它與下面的聲明的不同之處:

1
extern char* strcpy(char*,const char*);

下面的這個聲明僅表示在連接的時候調用strcpy()。

extern "C"指令非常有用,因為C和C++的近親關系。注意:extern "C"指令中的C,表示的一種編譯和連接規約,而不是一種語言。C表示符合C語言的編譯和連接規約的任何語言,如Fortran、assembler等。

還有要說明的是,extern "C"指令僅指定編譯和連接規約,但不影響語義。例如在函數聲明中,指定了extern "C",仍然要遵守C++的類型檢測、參數轉換規則。

再看下面的一個例子,為了聲明一個變數而不是定義一個變數,你必須在聲明時指定extern關鍵字,但是當你又加上了"C",它不會改變語義,但是會改變它的編譯和連接方式。

如果你有很多語言要加上extern "C",你可以將它們放到extern "C"{ }中。

2.3、小結extern "C"

通過上面兩節的分析,我們知道extern "C"的真實目的是實現類C和C++的混合編程。在C++源文件中的語句前面加上extern "C",表明它按照類C的編譯和連接規約來編譯和連接,而不是C++的編譯的連接規約。這樣在類C的代碼中就可以調用C++的函數or變數等。(註:我在這里所說的類C,代表的是跟C語言的編譯和連接方式一致的所有語言)

3、C和C++互相調用

我們既然知道extern "C"是實現的類C和C++的混合編程。下面我們就分別介紹如何在C++中調用C的代碼、C中調用C++的代碼。首先要明白C和C++互相調用,你得知道它們之間的編譯和連接差異,及如何利用extern "C"來實現相互調用。

3.1、C++的編譯和連接

C++是一個面向對象語言(雖不是純粹的面向對象語言),它支持函數的重載,重載這個特性給我們帶來了很大的便利。為了支持函數重載的這個特性,C++編譯器實際上將下面這些重載函數:

1
void print(int i);

2
void print(char c);

3
void print(float f);

4
void print(char* s);

編譯為:

1
_print_int

2
_print_char

3
_print_float

4
_pirnt_string

這樣的函數名,來唯一標識每個函數。註:不同的編譯器實現可能不一樣,但是都是利用這種機制。所以當連接是調用print(3)時,它會去查找_print_int(3)這樣的函數。下面說個題外話,正是因為這點,重載被認為不是多態,多態是運行時動態綁定(「一種介面多種實現」),如果硬要認為重載是多態,它頂多是編譯時「多態」。

C++中的變數,編譯也類似,如全局變數可能編譯g_xx,類變數編譯為c_xx等。連接是也是按照這種機制去查找相應的變數。

3.2、C的編譯和連接

C語言中並沒有重載和類這些特性,故並不像C++那樣print(int
i),會被編譯為_print_int,而是直接編譯為_print等。因此如果直接在C++中調用C的函數會失敗,因為連接是調用C中的print(3)時,它會去找_print_int(3)。因此extern
"C"的作用就體現出來了。

3.3、C++中調用C的代碼

假設一個C的頭文件cHeader.h中包含一個函數print(int i),為了在C++中能夠調用它,必須要加上extern關鍵字(原因在extern關鍵字那節已經介紹)。它的代碼如下:

1
#ifndef C_HEADER

2
#define C_HEADER

3

4
extern void print(int i);

5

6
#endif C_HEADER

相對應的實現文件為cHeader.c的代碼為:

1
#include <stdio.h>

2
#include "cHeader.h"

3
void print(int i)

4
{

5
printf("cHeader %d\n",i);

6
}

現在C++的代碼文件C++.cpp中引用C中的print(int i)函數:

1
extern "C"{

2
#include "cHeader.h"

3
}

4

5
int main(int argc,char** argv)

6
{

7
print(3);

8
return 0;

9
}

執行程序輸出:

3.4、C中調用C++的代碼

現在換成在C中調用C++的代碼,這與在C++中調用C的代碼有所不同。如下在cppHeader.h頭文件中定義了下面的代碼:

1
#ifndef CPP_HEADER

2
#define CPP_HEADER

3

4
extern "C" void print(int i);

5

6
#endif CPP_HEADER

相應的實現文件cppHeader.cpp文件中代碼如下:

1
#include "cppHeader.h"

2

3
#include <iostream>

4
using namespace std;

5
void print(int i)

6
{

7
cout<<"cppHeader "<<i<<endl;

8
}

在C的代碼文件c.c中調用print函數:

1
extern void print(int i);

2
int main(int argc,char** argv)

3
{

4
print(3);

5
return 0;

6
}

注意在C的代碼文件中直接#include "cppHeader.h"頭文件,編譯出錯。而且如果不加extern int print(int i)編譯也會出錯。

4、C和C++混合調用特別之處函數指針

當我們C和C++混合編程時,有時候會用一種語言定義函數指針,而在應用中將函數指針指向另一中語言定義的函數。如果C和C++共享同一中編譯和連接、函數調用機制,這樣做是可以的。然而,這樣的通用機制,通常不然假定它存在,因此我們必須小心地確保函數以期望的方式調用。

而且當指定一個函數指針的編譯和連接方式時,函數的所有類型,包括函數名、函數引入的變數也按照指定的方式編譯和連接。如下例:

01
typedef int (*FT) (const void* ,const void*);//style of C++

02

03
extern "C"{

04
typedef int (*CFT) (const void*,const void*);//style of C

05
void qsort(void* p,size_t n,size_t sz,CFT cmp);//style of C

06
}

07

08
void isort(void* p,size_t n,size_t sz,FT cmp);//style of C++

09
void xsort(void* p,size_t n,size_t sz,CFT cmp);//style of C

10

11
//style of C

12
extern "C" void ysort(void* p,size_t n,size_t sz,FT cmp);

13

14
int compare(const void*,const void*);//style of C++

15
extern "C" ccomp(const void*,const void*);//style of C

16

17
void f(char* v,int sz)

18
{

19
//error,as qsort is style of C

20
//but compare is style of C++

21
qsort(v,sz,1,&compare);

22
qsort(v,sz,1,&ccomp);//ok

23

24
isort(v,sz,1,&compare);//ok

25
//error,as isort is style of C++

26
//but ccomp is style of C

27
isort(v,sz,1,&ccopm);

28
}

注意:typedef int (*FT) (const void* ,const void*),表示定義了一個函數指針的別名FT,這種函數指針指向的函數有這樣的特徵:返回值為int型、有兩個參數,參數類型可以為任意類型的指針(因為為void*)。

最典型的函數指針的別名的例子是,信號處理函數signal,它的定義如下:

1
typedef void (*HANDLER)(int);

2
HANDLER signal(int ,HANDLER);

上面的代碼定義了信函處理函數signal,它的返回值類型為HANDLER,有兩個參數分別為int、HANDLER。 這樣避免了要這樣定義signal函數:

1
void (*signal (int ,void(*)(int) ))(int)

比較之後可以明顯的體會到typedef的好處。

I. 編譯原理 A產生空和B的規約在一個項目集里是規約沖突嗎

如果我們把同心的項目集合合並為一,就可能導致沖突,但是這種沖突不會是移進-規約沖突.因為如果存在這種沖突,則意味著對當前輸入符號a,有一個項目[A→α.,a]要求以A→α進行規約,同時又有另一個項目[B→β.aγ,b]要求把a移進.這兩個項目既然同處於合並之後的項目集中,則意味著在合並前,必有某個c使得[A→α.,a]和[B→β.aγ,c]同處於合並前的某一集合中.然而,這又意味著原來的LR(1)項目集就已經存在移進-規約沖突.從而文法不是LR(1)的,這與假設不符.事實上移進-規約沖突不依賴於搜索符號而只依賴於其心,因此,同心集合的合並不會引起新的移進-規約沖突

熱點內容
銀行密碼保護在哪裡 發布:2024-04-27 10:25:23 瀏覽:188
tomcat源碼導入eclipse 發布:2024-04-27 10:25:15 瀏覽:193
android的api 發布:2024-04-27 10:23:39 瀏覽:682
官式訪問 發布:2024-04-27 10:04:00 瀏覽:521
國產高配置有哪些 發布:2024-04-27 09:18:26 瀏覽:947
建行手機app忘記密碼如何修改 發布:2024-04-27 08:58:59 瀏覽:393
蟻群演算法的數學模型 發布:2024-04-27 08:58:39 瀏覽:994
androidactivity生命 發布:2024-04-27 07:33:48 瀏覽:84
win2008伺服器搭建網站 發布:2024-04-27 07:26:51 瀏覽:640
java的vector 發布:2024-04-27 07:05:00 瀏覽:204