免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Linux GNU C對(duì)標(biāo)準(zhǔn)C語言的擴(kuò)展與增強(qiáng)

正文


Linux 上可用的 C 編譯器是 GNU C 編譯器,它建立在自由軟件基金會(huì)的編程許可證的基礎(chǔ)上,因此可以自由發(fā)布。GNU C對(duì)標(biāo)準(zhǔn)C進(jìn)行一系列擴(kuò)展,以增強(qiáng)標(biāo)準(zhǔn)C的功能。

1.零長度和變量長度數(shù)組

GNU C允許使用零長度數(shù)組,在定義變長對(duì)象的頭結(jié)構(gòu)時(shí),這個(gè)特性非常有用。例如:

struct var_data { 
    int len; 
    char data[0]; 
};

char data[0]僅僅意味著程序中通過var_data結(jié)構(gòu)體實(shí)例的data[index]成員可以訪問len之后的第index個(gè)地址,它并 沒有為data[]數(shù)組分配內(nèi)存,因此sizeof(struct var_data)=sizeof(int)。

假設(shè)struct var_data的數(shù)據(jù)域就保存在struct var_data緊接著的內(nèi)存區(qū)域中,則通過如下代碼可以遍歷這些數(shù)據(jù):

struct var_data s; 
... 
for (i = 0; i < s.len; i++) 
    printf('%02x', s.data[i]);

GNU C中也可以使用1個(gè)變量定義數(shù)組,例如如下代碼中定義的“double x[n]”:

int main (int argc, char *argv[]) 

    int i, n = argc; 
    double x[n]; 
    for (i = 0; i < n; i++) 
        x[i] = i; 
    return 0
}

2.case范圍

GNU C支持case x…y這樣的語法,區(qū)間[x,y]中的數(shù)都會(huì)滿足這個(gè)case的條件,請(qǐng)看下面的代碼:

switch (ch) { 
case '0'... '9': c -= '0'
    break;
case 'a'... 'f': c -= 'a' - 10
    break
case 'A'... 'F': c -= 'A' - 10
    break
}

代碼中的case'0'...'9'等價(jià)于標(biāo)準(zhǔn)C中的:

case '0'case '1'case '2'case '3'case '4'
case '5'case '6'case '7'case '8'case '9':

3.語句表達(dá)式

GNU C把包含在括號(hào)中的復(fù)合語句看成是一個(gè)表達(dá)式,稱為語句表達(dá)式,它可以出現(xiàn)在任何允許表達(dá)式的地 方。我們可以在語句表達(dá)式中使用原本只能在復(fù)合語句中使用的循環(huán)、局部變量等,例如:

#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 = min_t(float, fa, fb);

因?yàn)橹匦露x了__xx和__y這兩個(gè)局部變量,所以用上述方式定義的宏將不會(huì)有副作用。在標(biāo)準(zhǔn)C中,對(duì)應(yīng)的如 下宏則會(huì)產(chǎn)生副作用:

#define min(x,y) ((x) < (y) (x) : (y))

代碼min(++ia,++ib)會(huì)展開為((++ia)<(++ib)(++ia):(++ib)),傳入宏的“參數(shù)”增加兩次。

4.typeof關(guān)鍵字

typeof(x)語句可以獲得x的類型,因此,可以借助typeof重新定義min這個(gè)宏:

#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)那個(gè)宏那樣把type傳入,因?yàn)橥ㄟ^typeof(x)、typeof(y)可以獲得type。代 碼行(void)(&_x==&_y)的作用是檢查_x和_y的類型是否一致。

5.可變參數(shù)宏

標(biāo)準(zhǔn)C就支持可變參數(shù)函數(shù),意味著函數(shù)的參數(shù)是不固定的,例如printf()函數(shù)的原型為:

int printfconst char *format [, argument]... );

而在GNU C中,宏也可以接受可變數(shù)目的參數(shù),例如:

#define pr_debug(fmt,arg...) \ 
printk(fmt,##arg)

這里arg表示其余的參數(shù),可以有零個(gè)或多個(gè)參數(shù),這些參數(shù)以及參數(shù)之間的逗號(hào)構(gòu)成arg的值,在宏擴(kuò)展時(shí)替換 arg,如下列代碼:

pr_debug('%s:%d',filename,line)

會(huì)被擴(kuò)展為:

printk('%s:%d', filename, line)

使用“##”是為了處理arg不代表任何參數(shù)的情況,這時(shí)候,前面的逗號(hào)就變得多余了。使用“##”之后,GNU C預(yù) 處理器會(huì)丟棄前面的逗號(hào),這樣,下列代碼:

pr_debug('success!\n')

會(huì)被正確地?cái)U(kuò)展為:

printk('success!\n')

而不是:

printk('success!\n',)

6.標(biāo)號(hào)元素

標(biāo)準(zhǔn)C要求數(shù)組或結(jié)構(gòu)體的初始化值必須以固定的順序出現(xiàn),在GNU C中,通過指定索引或結(jié)構(gòu)體成員名,允許 初始化值以任意順序出現(xiàn)。

指定數(shù)組索引的方法是在初始化值前添加“[INDEX]=”,當(dāng)然也可以用“[FIRST...LAST]=”的形式指定一個(gè)范圍。例如,下面的代碼定義了一個(gè)數(shù)組,并把其中的所有元素賦值為0:

unsigned char data[MAX] = { [0 ... MAX-1] = 0 };

下面的代碼借助結(jié)構(gòu)體成員名初始化結(jié)構(gòu)體:

struct file_operations ext2_file_operations = { 
    llseek: generic_file_llseek, 
    read: generic_file_read, 
    write: generic_file_write, 
    ioctl: ext2_ioctl, 
    mmap: generic_file_mmap, 
    open: generic_file_open, 
    release: ext2_release_file, 
    fsync: ext2_sync_file, 
};

但是,Linux 2.6推薦類似的代碼應(yīng)該盡量采用標(biāo)準(zhǔn)C的方式

struct file_operations ext2_file_operations = { 
    .llseek     = generic_file_llseek, 
    .read       = generic_file_read, 
    .write      = generic_file_write, 
    .aio_read   = generic_file_aio_read, 
    .aio_write  = generic_file_aio_write, 
    .ioct       = ext2_ioctl, 
    .mmap       = generic_file_mmap, 
    .open       = generic_file_open, 
    .release    = ext2_release_file, 
    .fsync      = ext2_sync_file, 
    .readv      = generic_file_readv, 
    .writev     = generic_file_writev, 
    .sendfile   = generic_file_sendfile, 
};

7.當(dāng)前函數(shù)名

GNU C預(yù)定義了兩個(gè)標(biāo)識(shí)符保存當(dāng)前函數(shù)的名字,__FUNCTION__保存函數(shù)在源碼中的名字,__PRETTY_FUNCTION__保存帶語言特色的名字。在C函數(shù)中,這兩個(gè)名字是相同的。

void example() 

    printf('This is function:%s', __FUNCTION__); 
}

代碼中的__FUNCTION__意味著字符串“example”。C99已經(jīng)支持__func__宏,因此建議在Linux編程中不再使用__FUNCTION__,而轉(zhuǎn)而使用__func__:

void example(void) 

    printf('This is function:%s', __func__); 
}

8.特殊屬性聲明

GNU C允許聲明函數(shù)、變量和類型的特殊屬性,以便手動(dòng)優(yōu)化代碼和定制代碼檢查的方法。要指定一個(gè)聲明的 屬性,只需要在聲明后添加__attribute__((ATTRIBUTE))。其中ATTRIBUTE為屬性說明,如果存在多個(gè)屬 性,則以逗號(hào)分隔。GNU C支持noreturn、format、section、aligned、packed等十多個(gè)屬性。

noreturn屬性作用于函數(shù),表示該函數(shù)從不返回。這會(huì)讓編譯器優(yōu)化代碼,并消除不必要的警告信息。例如:

define ATTRIB_NORET __attribute__((noreturn)) .... 
asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET;

format屬性也用于函數(shù),表示該函數(shù)使用printf、scanf或strftime風(fēng)格的參數(shù),指定format屬性可以讓編譯器根據(jù)格 式串檢查參數(shù)類型。例如:

asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf12)));

上述代碼中的第1個(gè)參數(shù)是格式串,從第2個(gè)參數(shù)開始都會(huì)根據(jù)printf()函數(shù)的格式串規(guī)則檢查參數(shù)。

unused屬性作用于函數(shù)和變量,表示該函數(shù)或變量可能不會(huì)用到,這個(gè)屬性可以避免編譯器產(chǎn)生警告信息。

aligned屬性用于變量、結(jié)構(gòu)體或聯(lián)合體,指定變量、結(jié)構(gòu)體或聯(lián)合體的對(duì)齊方式,以字節(jié)為單位,例如:

struct example_struct { 
    char a; 
    int b; 
    long c; 
} __attribute__((aligned(4)));

表示該結(jié)構(gòu)類型的變量以4字節(jié)對(duì)齊。

packed屬性作用于變量和類型,用于變量或結(jié)構(gòu)體成員時(shí)表示使用最小可能的對(duì)齊,用于枚舉、結(jié)構(gòu)體或聯(lián)合體類型時(shí)表示該類型使用最小的內(nèi)存。例如:

struct example_struct { 
    char a; 
    int b; 
    long c __attribute__((packed)); 
};

編譯器對(duì)結(jié)構(gòu)體成員及變量對(duì)齊的目的是為了更快地訪問結(jié)構(gòu)體成員及變量占據(jù)的內(nèi)存。例如,對(duì) 于一個(gè)32位的整型變量,若以4字節(jié)方式存放(即低兩位地址為00),則CPU在一個(gè)總線周期內(nèi)就可以讀取32 位;否則,CPU需要兩個(gè)總線周期才能讀取32位。

9.內(nèi)建函數(shù)

GNU C提供了大量內(nèi)建函數(shù),其中大部分是標(biāo)準(zhǔn)C庫函數(shù)的GNU C編譯器內(nèi)建版本,例如memcpy()等,它們與對(duì)應(yīng)的標(biāo)準(zhǔn)C庫函數(shù)功能相同。

不屬于庫函數(shù)的其他內(nèi)建函數(shù)的命名通常以__builtin開始,如下所示。

內(nèi)建函數(shù)__builtin_return_address(LEVEL)返回當(dāng)前函數(shù)或其調(diào)用者的返回地址,參數(shù)LEVEL指定調(diào)用棧的級(jí)數(shù),如0表示當(dāng)前函數(shù)的返回地址,1表示當(dāng)前函數(shù)的調(diào)用者的返回地址。

內(nèi)建函數(shù)__builtin_constant_p(EXP)用于判斷一個(gè)值是否為編譯時(shí)常數(shù),如果參數(shù)EXP的值是常數(shù),函數(shù)返回1,否則返回0。例如,下面的代碼可檢測(cè)第1個(gè)參數(shù)是否為編譯時(shí)常數(shù)以確定采用參數(shù)版本還是非參數(shù)版本:

#define test_bit(nr,addr) \ 
(__builtin_constant_p(nr) \ 
constant_test_bit((nr),(addr)) : \ 
variable_test_bit((nr),(addr)))

內(nèi)建函數(shù)__builtin_expect(EXP,C)用于為編譯器提供分支預(yù)測(cè)信息,其返回值是整數(shù)表達(dá)式EXP的值,C的 值必須是編譯時(shí)常數(shù)。

Linux內(nèi)核編程時(shí)常用的likely()和unlikely()底層調(diào)用的likely_notrace()、unlikely_notrace()就是基于 __builtin_expect(EXP,C)實(shí)現(xiàn)的。

#define likely_notrace(x) __builtin_expect(!!(x), 1) 
#define unlikely_notrace(x) __builtin_expect(!!(x), 0)

若代碼中出現(xiàn)分支,則即可能中斷流水線,我們可以通過likely()和unlikely()暗示分支容易成立還是不容易 成立,例如:

if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev)))
    if (ipv4_is_loopback(saddr)) 
    goto e_inval;

在使用gcc編譯C程序的時(shí)候,如果使用“-ansi–pedantic”編譯選項(xiàng),則會(huì)告訴編譯器不使用GNU擴(kuò)展語法。例如對(duì) 于如下C程序test.c:

struct var_data { 
    int len; 
    char data[0]; 
};
struct var_data a;

直接編譯可以通過:

gcc -c test.c

如果使用“-ansi–pedantic”編譯選項(xiàng),編譯會(huì)報(bào)警:

gcc -ansi -pedantic -c test.c 
test.c:3: warning: ISO C forbids zero-size array 'data'

原文來源于:作者:AaronLee;

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
GNU C 與 ANSI C_風(fēng)繼續(xù)吹
GNU C 擴(kuò)展之__attribute__ 機(jī)制簡介|GNU,C 擴(kuò)展,__attribute__ 機(jī)制
GNU C與ANSI C
Linux程序設(shè)計(jì)——用getopt處理命令行參數(shù)
C語言學(xué)習(xí)教程第七章-結(jié)構(gòu)與聯(lián)合(4)
C語言學(xué)習(xí)筆記【結(jié)構(gòu)體02】結(jié)構(gòu)體指針變量與結(jié)構(gòu)體變量的函數(shù)參數(shù)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服