C/C++定義與聲明

《C++ Primer》中文第四版對變量的定義與聲明做如下定義:
	1、變量的定義(definition)用於爲變量分配存儲空間,還可以爲變量指定初始值。在一個程序中,變量有且僅有一次定義。
	2、聲明(declaration)用於向程序表明變量的類型和名字。定義也是聲明:當定義變量時我們聲明瞭它的類型和名字;

(下面是來自:http://blog.csdn.net/binghehjbenben/article/details/7791224 關於聲明與定義進行了更加詳細的討論)


C變量聲明或定義時,需要類型說明符、存儲類型、類型限定符。類型說明符就是,能夠說明某個變量是什麼類型的就是類型說明符,比如:int、double、char、指針、結構體、枚舉等等,只要它能夠說明變量是什麼類型的就是類型說明符。
C存儲類型說明符,包括extern,static,register,auto。默認的存儲類型爲auto。

             函數和全局變量具有外部連接,這意味着他們對構成程序的所有文件都是可用的.

            聲明爲Static的的文件域對象具有內部連接,只在聲明他的文件中可用.

            局部變量沒有連接, 因此只在聲明他的塊中可用.

            聲明表述對象的名稱和類型,定義則是導致爲對象分配內存空間.

           Extern 的重要用途和多文件程序有關,C允許程序分散在兩個或者多個文件中,分別編譯然後再連接到一起.在這種情況下,必須以某中方式,將程序所需要的全局變量通知所有的文件.最簡單的辦法就是在一個文件中定義所有的全局變量,在另一個文件中用Extern聲明. Extern 的作用是通知編譯程序,告訴其後類型和名字的變量已經別的地方定義.換句話說Extern使編譯程序瞭解變量的名字和類型同時又不再爲他們分配內存.

           Static 的局部變量是函數或者文件中的永久變量.和全局變量不同 在函數或者文件外是看不到靜態局部變量的.和全局變量相同的是他被分配固定的內存空間.這樣在函數調用之間靜態變量保持其值.在多次函數調用之間保持其值的局部變量.

           Static的全局變量另編譯程序生成靜態全局變量.使之只在定義該變量的文件中可見.雖然變量是全局的但是起他文件的程序無法感知他的存在,無法對他進行修改.

         小結: 局部的景泰變量名只在他們被聲明的代碼塊中是認知的,全局的靜態變量只在他們被聲明的文件中可見,可修改的.

        Register任何類型的變量,在實踐中 Register告訴編譯程序把被他說明的     字符型和整數存放到CPU寄存器裏面.而把其他的類型做適當的存儲優化,提高這些數據的存取速度.    但是Register 的存儲類型有一定的侷限, 他只能修飾 局部變量和 函數的形參..
        
        auto、register、static、extern是屬於存儲類修飾符。在聲明時,存儲類修飾符最多隻能使用一個,而且無法用在typeof聲明中。

而類型限定符是指const、volatile、restrict。聲明中可以使用多個類型限定符,順序沒有限制。另外,類型限制符可以用在typeof聲明中。

(1)const
對象的類型如果有const限定符,該對象就是常量;在定義該對象之後,就無法修改它。
具體見下面的例子:
int main()
{
char a[100];
char c[100];
int j=100;
char * p;
const char *b = a;
const int i = j;
const int v[] = {1, 2, 3, 4, 5, 6};
int *k;
strcpy(a, "hello world!");
strcpy(c, "hello China!");
b = c; //可以修改b的值
/
printf("b=[%s]\n", b);
printf("i=[%d]\n", i);
printf("v[0]=[%d]\n", v[0]);

return 1;
}

(2)volatile
對象的類型如果有volatile限定符,就可能會被其他執行程序或事件所修改。volatile關鍵字告訴編譯器在每次使用此對象的值時,都要重新讀取,即使程序本身並沒有修改它的值。

(3)restrict
restrict限定符只適用於對象指針類型。這是C99新增加的,用來告訴編譯器,此指針所指向的對象如果被修改,就不可以被此指針以外的方式所存取,不管是直接地還是間接地。

C語言關鍵字__restrict在Cell上的應用

今天看到在一篇FFT在Cell上的優化文章中,提到關鍵字__restrict,說是它可以減少一些指令之間的dependency。以前還沒有用過這個關鍵字,google了一下,有個理解比較好:
1. 首先我認爲restrict只能修飾參數爲指針類型的變量,否則沒有意義。
2. 它只能用於修飾函數參數,否則也沒有意義。
3. 編譯器對它的實現是:(用上面那個函數舉例,是個int *a加上int *b的函數)
把*a,*b都讀入寄存器中(第一次訪存),然後函數體內所有引用*a,*b的地方都使用寄存器裏的值,所有對它們的修改也寫入寄存器中,最後函數返回時,把寄存器中的值寫回a,b指向的地址(第二次訪存)。如果函數內部大量引用了a,b指向內存的值,這樣的策略可以大大減小訪存操作從而提高性能。當然,在x86機器上由於通用寄存器少,當寄存器溢出時,會爲*a,*b都生成一個copy(這就是所謂的alias),這樣反而會降低性能。但對於例如IA64這種有128個通用寄存器的機器來說,性能應該會大大提高。其實說了這麼多,一句“進/出拷貝”就可以說明實質。
4.最後我認爲restrict修飾集合類型的數據(例如struct)沒有意義,因爲對結構體的引用是多次訪存,無法通過把值加載到寄存器中而避免多餘的訪存操作。

在Cell編程中,有些指針只是用來存儲數據,某一個函數中總是訪問某一個指針的不同區域,這樣這個指針聲明爲__restrict是再好不過了,可以減少存取內存的操作,數據第一次載入寄存器後可以使用到函數退出才寫入內存(如果寄存器足夠容納這些數據)。

C99 中新增加了 restrict 修飾的指針: 由 restrict 修飾的指針是最初唯一對指針所指向的對象進行存取的方法,僅當第二個指針基於第一個時,才能對對象進行存取。對對象的存取都限定於基於由 restrict 修飾的指針表達式中。

由 restrict 修飾的指針主要用於函數形參,或指向由 malloc() 分配的內存空間。restrict 數據類型不改變程序的語義。 編譯器能通過作出 restrict 修飾的指針是存取對象的唯一方法的假設,更好地優化某些類型的例程。

[典型例子] memcpy() 在 C99 中,restrict 可明確用於 memcpy() 的原型,而在 C89 中必須進行解釋。 void *memcpy(void *restrict str1, const void *restrict str2, size_t size);

指針在聲明的時候可以用關鍵字restrict修飾,如
int *restrict p;

將告訴編譯器,指針p是訪問p所指對象的唯一方式

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章