GNU C與ANSI C

來源:互聯網
上載者:User

從《LINUX裝置驅動開發詳解》裡面一字一句地打出來,放在這裡,供大家分享!

      LINUX系統上可用的C編譯器是GNU C編譯器,它建立在自由軟體基金會的編程許可的基礎上,因此可以自由發布。GNU C對標準C進行了一系列的擴充,以增強標準C的功能。
1、零長度數組
GNU C允許使用零長度數組,在定義變長對象的頭結構時,這個特性特別有用。例如:
struct var_data
{
int len;
char data[0];
};
char data[0]僅僅意味著程式中通過var_data結構執行個體的data[index]成員可以訪問len之後的第index個地址,它並沒有為data[]數組分配記憶體,因此sizeof(struct var_data)=sizeof(int).
假設struct var_data的資料域儲存在struct var_data緊接著的記憶體地區,通過如下代碼可以遍曆這些資料:
struct var_data s;
...
for(i = 0;i < s.len;i++)
{
printf("%02x",s.data[i]);
}
2.case 範圍
GNU C支援case x...y這樣的文法,區間[x,y]的數都會滿足這個case的條件,請看下面的代碼:
switch(ch)
{
case '0'...'9':c -= '0';
break;
case 'a'...'f':c -= 'a';
break;
}
代碼中的case '0'...'9'等價於標準C中的如下代碼:
case '0':
case '1':
...
case '9':
3.語句運算式
GNU C把包含在括弧中的複合陳述式看做是一個運算式,稱為語句運算式,它可以出現在任何允許運算式的地方。我們可以在語句運算式中使用原本只能在複合陳述式中使用的迴圈變數、局部變數等,例如:
#define min_t(type,x,y) \
({ type __x = (x);type __y = (y); __x < __y ? __x : __y;})
int ia,ib,mini;
float fa,fb,minf;

mini = min_t(int ,ia ,ib);
minf = mini_t(float ,ia, ib);
因為重新定義了__x,__y這兩個局部變數,所以以上述方式定義的宏將不會產生副作用。在標C中,對應的如下宏則會產生副作用:
#define min(x,y) ((x)<(y)?(x):(y))
代碼min(++ia,++ib)會被展開為((++ia) < (++ib)?:(++ia):(++ib)),傳入的宏的參數被增加了兩次。
4、typeof關鍵字
typeof(x)語句可以獲得x的類型,因此,我們可以藉助typedef重新定義min這個宏:
#define min(x,y)\
(const typeof(x) __x = (x); \
(const typeof(y) __y = (y); \
(void)(&__x == &__y);
__x < __y ? __x :__y;})
我們不需要像min_t(type,x,y)這個宏那樣把type傳入,因為通過關鍵字就可以獲得type。程式碼 (void)(&__x == &__y);作用是檢查__x,__y類型是否一致!
5、可變參數的宏
標C只支援可變參數的函數,意味著函數的參數是不固定的,例如printf()函數原型:
int printf( const char *format[,argument]...);
而在GNU C中,宏也可以接受可變數目的參數,例如:
#define pr_debug(fmt,arg...) \
printk(fmt,##arg)
這裡的arg表示其餘的參數可以是零個或多個,這些參數以及參數之間的逗號構成arg的值,在宏擴充時替換arg,例如下列代碼:
pr_debug("%s:%d",filename,line)
會被擴充為:
printk("%s:%d",filename,line)
使用##的原因是處理arg不代表任何參數的情況,這時候,前面的逗號就變得多餘了。使用##之後,GNU C前置處理器會丟棄前面的括弧,這樣,代碼:
pr_debug("success")
會被擴充為:
printk("success")
而不是:
printk("success",)
6、標號元素
標C中要求數組或結構體的初始化值必須以固定的順序出現,在GNU C中,通過指定索引或結構體成員名,允許初始化值以任意順序出現。
指定數組索引的方法是在初始化值前添加“[INDEX]”,當然也可以用“[FIRST...LAST]=”形式指定一個範圍。例如定義一個數組,將其所有元素初始化為0:
unsigned char data[MAX] = {[0...MAX-1]=0};
而結構體的初始化:
{
.llseek = generic_file_llseek;
};
7、當前函數名
GNU C預定義了兩個標示符儲存當前函數的名字,__FUNCTION__儲存函數在源碼中的名字,__PRETTY_FUNCTION__儲存帶語言特色的名字。在C中,這兩個名字是相同的。即只是字串;
8、特殊屬性聲明
GNU C允許聲明函數、變數和類型的特殊屬性,以便進行手工的代碼最佳化和定製代碼檢查的方法。指定一個聲明的屬性,只需要在申明後添加 __attribute__((ATTRIBUTE))
其中ATTRIBUTE為屬性說明,如果存在多個屬性,則以逗號分隔。GNU C支援noreturn format section aligned packed等十多個屬性
* noreturn屬性作用於函數,表示該函數從不返回。這會讓編譯器最佳化代碼,並消除不必要的的警告資訊。例如
#define ATTRIB_NORET __attribute__ ((noreturn)) ....
asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET;
*format屬性也可用於函數,表示該函數printf scanf 或strftime風格的參數,指定format屬性可以讓編譯器根據格式串檢查參數類型。例如:
asmlinkage int printk(const char * fmt,...)\
__attribute__((format(printf,1,2)));
*unused屬性作用於函數和變數,表示該函數或變數可能不會被用到,避免編譯器產生的警告資訊。
*packed屬性作用於變數和類型,表示壓縮結構體,使用最小的記憶體。
struct examprl_struct
{
char a;
int b;
long c;
}__attribute__((packed));
注意,這個__attribute__((packed))只能用在GNU C;

   *section ("section-name")
屬性 section 用於函數和變數,通常編譯器將函數放在 .text 節,變數放在.data 或 .bss 節,使用 section 屬性,可以讓編譯器將函數或變數放在指定的節中。例如:
++++ include/linux/init.h
78: #define __init          __attribute__ ((__section__ (".text.init")))
79: #define __exit          __attribute__ ((unused, __section__(".text.exit")))
80: #define __initdata      __attribute__ ((__section__ (".data.init")))
81: #define __exitdata      __attribute__ ((unused, __section__ (".data.exit")))
82: #define __initsetup     __attribute__ ((unused,__section__ (".setup.init")))
83: #define __init_call     __attribute__ ((unused,__section__ (".initcall.init")))
84: #define __exit_call     __attribute__ ((unused,__section__ (".exitcall.exit")))
連接器可以把相同節的代碼或資料安排在一起,Linux 核心很喜歡使用這種技術,例如系統的初始化代碼被安排在單獨的一個節,在初始化結束後就可以釋放這部分記憶體。
* aligned (ALIGNMENT)
屬性 aligned 用於變數、結構或等位型別,指定變數、結構域、結構或聯合的對齊量,以位元組為單位,例如:
++++ include/asm-i386/processor.h
294: struct i387_fxsave_struct {
295:         unsigned short  cwd;
296:         unsigned short  swd;
297:         unsigned short  twd;
298:         unsigned short  fop;
299:         long    fip;
300:         long    fcs;
301:         long    foo;
......
308: } __attribute__ ((aligned (16)));
表示該結構類型的變數以 16 位元組對齊。通常編譯器會選擇合適的對齊量,顯示指定對齊通常是由於體系限制、最佳化等原因。
* packed
屬性 packed 用於變數和類型,用於變數或結構域時表示使用最小可能的對齊,用於枚舉、結構或等位型別時表示該類型使用最小的記憶體。例如:
++++ include/asm-i386/desc.h
51: struct Xgt_desc_struct {
52:         unsigned short size;
53:         unsigned long address __attribute__((packed));
54: };
域 address 將緊接著 size 分配。屬性 packed 的用途大多是定義硬體相關的結
構,使元素之間沒有因對齊而造成的空洞。

9、內建函數
GNU C提供了大量的內建函數,其中大部分是標C庫函數的GNU C編譯器的內建版本。
不屬於庫函數的其它內建函數的命名通常以__builtin開始;如下所示:
__builtin_return_address(LEVEL);

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.