標記化結構初始化語法(C語言)

 以前在看Linux代碼時,就對它的結構體初始化寫法感到奇怪,所有的初始化代碼都寫清了變量名,並且變量名前面還有一個詭異的點。最近學習Linux設備驅動,又遇到了,就查了一下,發現自己的知識果然紕漏不少,此種初始化寫法並不是什麼特殊的代碼風格,而是所謂的C語言標記化結構初始化語法(designated initializer),而且還是一個ISO標準。

 GNU C 標記化結構初始化方法----結構體成員前加小數點

struct a{

int b;

int c;

}

有幾種初始化方式:

struct a a1={

.b = 1,

.c =  2

};

或者 struct a a1={

b:1,

c:2

};

或者 struct a a1={1,2};

內核喜歡使用第一種,使用第一種和第二種,成員初始化順序可變。

C99支持結構的指定初始化項目,其語法與數組的指定初始化項目近似。只是,結構的指定初始化項目使用點運算符和成員名(而不是方括號和索引值)來標識具體的元素。例如,只初始化book結構的成員vlaue,可以這樣做:

  1. struct book surprise = { .value = 10.99 };

可以按照任意的順序使用指定初始化項目:

struct book gift = {

.value = 25.99,

.author = "James Broadfool",

.title = "Rue for the Toad"

};

正像數組一樣,跟在一個指定初始化項目之後的常規初始化項目爲跟在指定成員後的成員提供了初始值。另外,對特定成員的最後一次賦值是它實際獲得的值

例如,考慮如下聲明:struct book gift = {

 .value = 18.90,

.author = "Philionna pestle",

0.25};

這將把值0.25賦給成員vlaue,因爲它在結構聲明中緊跟在author成員之後。新的值0.25代替了早先的賦值18.90。

  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. struct operators   
  4. {   
  5.      void (*read1)(char *);   
  6.      void (*read2)(char *);   
  7.      void (*read3)(char *);   
  8.      int n;   
  9. };   
  10.    
  11. void read1(char *data)   
  12. {   
  13.      printf("read1: %s/n",data);   
  14. }   
  15. void read2(char *data)   
  16. {   
  17.      printf("read2: %s/n",data);   
  18. }   
  19. void read3(char *data)   
  20. {   
  21.      printf("read3: %s/n",data);   
  22. }   
  23.    
  24. int main()   
  25. {    //傳統的初始化方法   
  26.      //struct operators my_op = {read1, read2, read3, 100};    //所謂的標記化結構初始化語法   
  27.      struct operators my_op = {.read2 = read2,   
  28.                                .read1 = read1,   
  29.                                .read3 = read3,   
  30.                                .n = 100};   
  31.      my_op.read1("wangyang");   
  32.      my_op.read2("wangyang");   
  33.      my_op.read3("wangyang");   
  34.      return 0;   
  35. }  

 

重點就在於main()函數中對my_op結構體的初始化語句,使用點加變量名進行初始化。用過python的人會馬上感覺到這與關鍵字傳參是多麼的相似。

 

那它的好處在哪裏呢?我想好處有三:

    首先,標記傳參不用理會參數傳遞的順序,正如我上面的例子表示的那樣,我是先初始化了read2,然後再初始化了read1,程序員不用記憶參數的順序;

    其次,我們可以選擇性傳參,在傳統C語言順序傳參中,如果你只想對第三個變量進行初始化,那麼你不得不給第一個, 第二個參數進行初始化,而有時候一個變量並沒有很合適的默認值,而使用標記初始化法,你可以相當自由地對你有把握的參數進行初始化;

    第三,擴展性更好,如果你要在該結構體中增加一個字段,傳統方式下,爲了考慮代碼修改量,你最好將新添加的字段放在這個結構體的最後面,否則你將要面對大量且無趣的修改,你可能覺得放在哪裏沒什麼關係,但是我們都習慣了,姓名下面是性別,性別下面是年齡,接着是興趣愛好,最後是事蹟描述,如果年齡放在了最後面,難道不彆扭麼?!

 

有人提到,該種語法還有利於提高性能,木有感覺出來,我在這裏就不談這點了。

 

其實,該種初始化語法並不是什麼新技術,新定義,它就是ISO C99的一個標準用法,也就是說99年就有了,再說Linus也不會去趕什麼時髦的,據說C Primer Plus第五版中提到了這點,不過,我沒有看過該書,遺憾,我是直接投入了面向對象的懷抱。

 

GCC有擴展標記化結構初始化語法,寫法是下面這樣的:

struct operators my_op = {read2 : read2, read1 : read1, read3 : read3,};

 

 

轉自: http://www.hustyx.com/cplusplus/agtodXN0eWl4aWFuZ3IPCxIHQXJjaGl2ZRihigcM

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