一、類型限定詞volatile
限定詞volatile告訴編譯器該變量除了可以被程序改變以外還可被其他代理改變。
它通常被用于硬件地址和與其它并行運(yùn)行的程序共享的數(shù)據(jù)。
如:
volatile int locl;
volatile int *ploc;
你可能會(huì)奇怪為什么ANSI覺得有必要把volatile作為一個(gè)關(guān)鍵字。
原因是它可以方便編譯器優(yōu)化。
例如
一個(gè)聰明的編譯器可能注意到你使用了兩次x,而沒有改變它的值。那么,它有可能把x臨時(shí)存儲(chǔ)在一個(gè)寄存器中。
接著,當(dāng)val2需要x時(shí),可以通過從寄存器而非初始的內(nèi)存位置中讀取該值以節(jié)省時(shí)間。
這個(gè)過程被稱為緩存(caching)。
通常,緩存是一個(gè)好的優(yōu)化方式,但是如果在兩個(gè)語句間其他代理改變了x的話就不是這樣了。
如果沒有規(guī)定volatile關(guān)鍵字,那么編譯器將無從得知這種改變是否可能發(fā)生。
在ANSI中,如果聲明中沒有volatile關(guān)鍵字,那么編譯器就可以假定一個(gè)值在使用過程中沒有被修改,它就可以試著優(yōu)
化代碼。
一個(gè)值可以同時(shí)是const 和 volatile。
例如,硬件時(shí)鐘一般設(shè)定為不能由程序改變,這一點(diǎn)使它成為const;
但它被程序以外的代理改變,這使它成為volatile.
那么我們可以這么聲明:
volatile const int loc;
const volatile int *ploc;
二、類型限定詞restrict
關(guān)鍵字restrict用來消除數(shù)據(jù)間的相關(guān)性,編譯器從而可以安排語句的并行執(zhí)行。
它只可以用于指針,并表明指針是訪問一個(gè)數(shù)據(jù)對(duì)象的唯一且初始的方式。
我們通過一個(gè)例子來看看:
int ar[10];
int * par = ar;
int * restrict restar = (int *)malloc (10 * sizeof (int));
注意,指針restar是訪問由malloc ()分配的內(nèi)存的唯一且初始的方式。
因此,它可以由關(guān)鍵字restrict限定。
而指針par既不是初始的,也不是訪問數(shù)組ar中數(shù)據(jù)的唯一方式,因此不可以把它限定為restrict。
考慮下面的語句:
for (n = 0; n < 10; n++)
{
par[n] += 5;
restar[n] += 5;
ar[n] *= 2;
par[n] += 3;
restar[n] += 3;
}
知道了restar是放問它所指向數(shù)據(jù)塊的唯一初始化方式,編譯器就可以用具有同樣效果的一條語句來代替包含restar的
兩個(gè)語句。
然而,編譯器將兩個(gè)包含par的語句精簡(jiǎn)為一個(gè)語句將導(dǎo)致計(jì)算錯(cuò)誤。
原因是ar[n] *= 2;這條語句在par[n] += 3之前已經(jīng)改變了par指針?biāo)赶驍?shù)據(jù)的值。
restrict的作用:幫助編譯器確定使指針進(jìn)行數(shù)值計(jì)算時(shí),是否可以進(jìn)行優(yōu)化。
可以將關(guān)鍵字restrict作為指針型函數(shù)參量的限定詞使用。
這意味著編譯器可以假定在函數(shù)體內(nèi)沒有其它標(biāo)識(shí)符修改指針指向的數(shù)據(jù),因而可以試著優(yōu)化代碼,反之則不然。
voie * memcpy (void * restrict s1, const void * restrict s2, size_t n);
關(guān)鍵字restrict有兩個(gè)讀者。
一個(gè)是編譯器,它告訴編譯器可以自由地去做一些有關(guān)優(yōu)化的假定。
一個(gè)是用于,它告訴用戶僅使用滿足restrict要求的參數(shù)。