標記化結構初始化語法 在結構體成員前加上小數點 如 “.open .write .close ”C99編譯器

今天在看串口驅動(四)的時候 有這樣一個結構體初始化 我很不理解 如下:

static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
14  [0] = {
15   .port = {
16    .lock  = SPIN_LOCK_UNLOCKED,
17    .iotype  = UPIO_MEM,
18    .irq  = IRQ_S3CUART_RX0,
19    .uartclk = 0,
20    .fifosize = 16,
21    .ops  = &s3c24xx_serial_ops,
22    .flags  = UPF_BOOT_AUTOCONF,
23    .line  = 0,//端口索引:0
24   }
25  },
26  [1] = {
27   .port = {
28    .lock  = SPIN_LOCK_UNLOCKED,
29    .iotype  = UPIO_MEM,
30    .irq  = IRQ_S3CUART_RX1,
31    .uartclk = 0,
32    .fifosize = 16,
33    .ops  = &s3c24xx_serial_ops,
34    .flags  = UPF_BOOT_AUTOCONF,
35    .line  = 1, //端口索引:1
36   }
37  },
38 #if NR_PORTS > 2
39
40  [2] = {
41   .port = {
42    .lock  = SPIN_LOCK_UNLOCKED,
43    .iotype  = UPIO_MEM,
44    .irq  = IRQ_S3CUART_RX2,
45    .uartclk = 0,
46    .fifosize = 16,
47    .ops  = &s3c24xx_serial_ops,
48    .flags  = UPF_BOOT_AUTOCONF,
49    .line  = 2, //端口索引:2
50   }
51  }
52 #endif
53 };

 

爲什麼會在成員函數前加上小數點呢?  我在網上游蕩了好一陣找到了“Felix 的博客”,內容如下:

 

標記化結構初始化語法

 

在Linux2.6內核中對結構體的定義形式發生了變化,不再支持原來的定義形式。

 

1  static struct tty_operations uart_ops =
2  {
3   .open  = uart_open,//串口打開
4   .close  = uart_close,//串口關閉
5   .write  = uart_write,//串口發送
6   .put_char = uart_put_char,//...
7   .flush_chars = uart_flush_chars,
8   .write_room = uart_write_room,
9   .chars_in_buffer= uart_chars_in_buffer,
10  .flush_buffer = uart_flush_buffer,
11  .ioctl  = uart_ioctl,
12  .throttle = uart_throttle,
13  .unthrottle = uart_unthrottle,
14  .send_xchar = uart_send_xchar,
15  .set_termios = uart_set_termios,
16  .stop  = uart_stop,
17  .start  = uart_start,
18  .hangup  = uart_hangup,
19  .break_ctl = uart_break_ctl,
20  .wait_until_sent= uart_wait_until_sent,
21 #ifdef CONFIG_PROC_FS
22  .read_proc = uart_read_proc, //proc入口讀函數
23 #endif
24  .tiocmget = uart_tiocmget,
25  .tiocmset = uart_tiocmset,
26 };

 

這個聲明採用了標記化結構初始化語法。這種寫法是值得采用的,因爲它使驅動程序在結構的定義發生變化時更具有可移植性,並且使代碼更加緊湊且易讀。標記化的初始化方法允許對結構成員進行重新排列。在某些場合下,將頻繁被訪問的成員放在相同的硬件緩存行上,將大大提高性能。

----LLD3

查到這裏 我發現一個關鍵字 “這個聲明採用了標記化結構初始化語法” 我就搜索“標記化結構初始化語法” 內容如下:

這是ISO C99的用法

C Primer Plus第五版中相關章節:

    已知一個結構,定義如下
struct book
{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};
    C99支持結構的指定初始化項目,其語法與數組的指定初始化項目近似。只是,結構的指定初始化項目使用點運算符和成員名(而不是方括號和索引值)來標識具體的元素。例如,只初始化book結構的成員value,可以這樣做:
    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賦給成員value,因爲它在結構聲明中緊跟在author成員之後。新的值0.25代替了早先的賦值18.90。

    有關designated initializer的進一步信息可以參考c99標準的6.7.8節Ininialization。

 

 

 

 

在憶向 的博客中寫到:

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

代碼舉例如下:

#include <stdio.h>
#include <stdlib.h>
struct operators
{
     void (*read1)(char *);
     void (*read2)(char *);
     void (*read3)(char *);
     int n;
};
 
void read1(char *data)
{
     printf("read1: %s/n",data);
}
void read2(char *data)
{
     printf("read2: %s/n",data);
}
void read3(char *data)
{
     printf("read3: %s/n",data);
}
 
int main()
{    //傳統的初始化方法
     //struct operators my_op = {read1, read2, read3, 100};    //所謂的標記化結構初始化語法
     struct operators my_op = {.read2 = read2,
                               .read1 = read1,
                               .read3 = read3,
                               .n = 100};
     my_op.read1("wangyang");
     my_op.read2("wangyang");
     my_op.read3("wangyang");
     return 0;
}重點就在於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,};

上面的例程爲什麼在vc++6.0中編譯怎麼通不過呢???

 

 

在 bluedrum  的空間中有篇 名爲《C版本差異--- 結構處理差別》的第3點中講到:

 

3、標記化結構初始化語法

在標準C中(C89(結構標準初始化是用{}來實始化,在C99的版本,採用了採用可讀性更強的標記化實始化,這在LINUX內核和驅動很爲常見。

其中VC++ 6.0只支持C89初始化,GCC支持自己標記化或自己擴展初始化。這種初始化採用 .name = value.這樣不需要按順序排序,方便調整實義,在大結構最大程度防止錯位的和調整定義帶來不便


struct name_str{
 int data;
 char name[120];
 int num;
};
/* 標記式初始化,注意順序不同,並可缺省 */
struct name_str str ={
  .num = 100;
  .name = "hxy";
 
};

/* C89 初始化 */

struct name_str str2 =
{
 100,"Andrew Huang",-2
};

/* gcc 擴展初始化 */
struct name_str str3 =
{
  name:"bluedrum";
  data:-1
}
}
 


個人想編譯 以上代碼 想下個C99編譯器 在百度搜索 C99編譯器   解決時間:2009-07-10 21:54 回答是

“VC++   2005支持的是C89  
  而不是C99  
  這點可以在一次對VS2005的負責人的採訪中看出來  
  他解釋了爲什麼VS2005支持C89   而不支持C99  
   
  目前完全支持C99標準的編譯器還不存在  
  支持部分C99標準的編譯器也不多  
  做的最好的是GCC”

查到這裏 終於明白這是個怎麼回事了 

截稿了

 

http://blog.csdn.net/windy_net/archive/2010/12/28/6103955.aspx

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