Linux 核心使用的 GNU C 擴充套件(轉)
Linux 核心使用的 GNU C 擴充套件(轉)[@more@]GNC CC 是一個功能非常強大的跨平臺 C 編譯器,它對 C 語言提供了很多擴充套件,
這些擴充套件對最佳化、目的碼佈局、更安全的檢查等方面提供了很強的支援。本文把
支援 GNU 擴充套件的 C 語言稱為 GNU C。
Linux 核心程式碼使用了大量的 GNU C 擴充套件,以至於能夠編譯 Linux 核心的唯一編
譯器是 GNU CC,以前甚至出現過編譯 Linux 核心要使用特殊的 GNU CC 版本的情
況。本文是對 Linux 核心使用的 GNU C 擴充套件的一個彙總,希望當你讀核心原始碼遇
到不理解的語法和語義時,能從本文找到一個初步的解答,更詳細的資訊可以檢視
gcc.info。文中的例子取自 Linux 2.4.18。
語句表示式
==========
GNU C 把包含在括號中的複合語句看做是一個表示式,稱為語句表示式,它可以出
現在任何允許表示式的地方,你可以在語句表示式中使用迴圈、區域性變數等,原本
只能在複合語句中使用。例如:
++++ include/linux/kernel.h
159: #define min_t(type,x,y)
160: ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
++++ net/ipv4/tcp_output.c
654: int full_space = min_t(int, tp->window_clamp, tcp_full_space(sk));
複合語句的最後一個語句應該是一個表示式,它的值將成為這個語句表示式的值。
這裡定義了一個安全的求最小值的宏,在標準 C 中,通常定義為:
#define min(x,y) ((x) < (y) ? (x) : (y))
這個定義計算 x 和 y 分別兩次,當引數有副作用時,將產生不正確的結果,使用
語句表示式只計算引數一次,避免了可能的錯誤。語句表示式通常用於宏定義。
Typeof
======
使用前一節定義的宏需要知道引數的型別,利用 typeof 可以定義更通用的宏,不
必事先知道引數的型別,例如:
++++ include/linux/kernel.h
141: #define min(x,y) ({
142: const typeof(x) _x = (x);
143: const typeof(y) _y = (y);
144: (void) (&_x == &_y);
145: _x < _y ? _x : _y; })
這裡 typeof(x) 表示 x 的值型別,第 142 行定義了一個與 x 型別相同的區域性變
量 _x 並初使化為 x,注意第 144 行的作用是檢查引數 x 和 y 的型別是否相同。
typeof 可以用在任何型別可以使用的地方,通常用於宏定義。
零長度陣列
==========
GNU C 允許使用零長度陣列,在定義變長物件的頭結構時,這個特性非常有用。例
如:
++++ include/linux/minix_fs.h
85: struct minix_dir_entry {
86: __u16 inode;
87: char name[0];
88: };
結構的最後一個元素定義為零長度陣列,它不佔結構的空間。在標準 C 中則需要
定義陣列長度為 1,分配時計算物件大小比較複雜。
可變引數宏
==========
在 GNU C 中,宏可以接受可變數目的引數,就象函式一樣,例如:
++++ include/linux/kernel.h
110: #define pr_debug(fmt,arg...)
111: printk(KERN_DEBUG fmt,##arg)
這裡 arg 表示其餘的引數,可以是零個或多個,這些引數以及引數之間的逗號構
成 arg 的值,在宏擴充套件時替換 arg,例如:
pr_debug("%s:%d",filename,line)
擴充套件為
printk("<7>" "%s:%d", filename, line)
使用 ## 的原因是處理 arg 不匹配任何引數的情況,這時 arg 的值為空,GNU
C 前處理器在這種特殊情況下,丟棄 ## 之前的逗號,這樣
pr_debug("success! ")
擴充套件為
printk("<7>" "success! ")
注意最後沒有逗號。
標號元素
========
標準 C 要求陣列或結構變數的初使化值必須以固定的順序出現,在 GNU C 中,通
過指定索引或結構域名,允許初始化值以任意順序出現。指定陣列索引的方法是在
初始化值前寫 '[INDEX] =',要指定一個範圍使用 '[FIRST ... LAST] =' 的形式,
例如:
+++++ arch/i386/kernel/irq.c
1079: static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
將陣列的所有元素初使化為 ~0UL,這可以看做是一種簡寫形式。
要指定結構元素,在元素值前寫 'FIELDNAME:',例如:
++++ fs/ext2/file.c
41: struct file_operations ext2_file_operations = {
42: llseek: generic_file_llseek,
43: read: generic_file_read,
44: write: generic_file_write,
45: ioctl: ext2_ioctl,
46: mmap: generic_file_mmap,
47: open: generic_file_open,
48: release: ext2_release_file,
49: fsync: ext2_sync_file,
50 };
將結構 ext2_file_operations 的元素 llseek 初始化為 generic_file_llseek,
元素 read 初始化為 genenric_file_read,依次類推。我覺得這是 GNU C 擴充套件中
最好的特性之一,當結構的定義變化以至元素的偏移改變時,這種初始化方法仍然
保證已知元素的正確性。對於未出現在初始化中的元素,其初值為 0。
Case 範圍
=========
GNU C 允許在一個 case 標號中指定一個連續範圍的值,例如:
++++ arch/i386/kernel/irq.c
1062: case '0' ... '9': c -= '0'; break;
1063: case 'a' ... 'f': c -= 'a'-10; break;
1064: case 'A' ... 'F': c -= 'A'-10; break;
case '0' ... '9':
相當於
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
宣告的特殊屬性
==============
GNU C 允許宣告函式、變數和型別的特殊屬性,以便手工的程式碼最佳化和更仔細的代
碼檢查。要指定一個宣告的屬性,在宣告後寫
__attribute__ (( ATTRIBUTE ))
其中 ATTRIBUTE 是屬性說明,多個屬性以逗號分隔。GNU C 支援十幾個屬性,這
裡介紹最常用的:
* noreturn
屬性 noreturn 用於函式,表示該函式從不返回。這可以讓編譯器生成稍微最佳化的
程式碼,最重要的是可以消除不必要的警告資訊比如未初使化的變數。例如:
++++ include/linux/kernel.h
47: # define ATTRIB_NORET __attribute__((noreturn)) ....
61: asmlinkage NORET_TYPE void do_exit(long error_code)
ATTRIB_NORET;
* format (ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)
屬性 format 用於函式,表示該函式使用 printf, scanf 或 strftime 風格的參
數,使用這類函式最容易犯的錯誤是格式串與引數不匹配,指定 format 屬性可以
讓編譯器根據格式串檢查引數型別。例如:
++++ include/linux/kernel.h?
89: asmlinkage int printk(const char * fmt, ...)
90: __attribute__ ((format (printf, 1, 2)));
表示第一個引數是格式串,從第二個引數起根據格式串檢查引數。
* unused
屬性 unused 用於函式和變數,表示該函式或變數可能不使用,這個屬性可以避免
編譯器產生警告資訊。
* 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 的用途大多是定義硬體相關的結
構,使元素之間沒有因對齊而造成的空洞。
當前函式名
==========
GNU CC 預定義了兩個標誌符儲存當前函式的名字,__FUNCTION__ 儲存函式在原始碼
中的名字,__PRETTY_FUNCTION__ 儲存帶語言特色的名字。在 C 函式中,這兩個
名字是相同的,在 C++ 函式中,__PRETTY_FUNCTION__ 包括函式返回型別等額外
資訊,Linux 核心只使用了 __FUNCTION__。
++++ fs/ext2/super.c
98: void ext2_update_dynamic_rev(struct super_block *sb)
99: {
100: struct ext2_super_block *es = EXT2_SB(sb)->s_es;
101:
102: if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
103: return;
104:
105: ext2_warning(sb, __FUNCTION__,
106: "updating to rev %d because of new feature flag, "
107: "running e2fsck is recommended",
108: EXT2_DYNAMIC_REV);
這裡 __FUNCTION__ 將被替換為字串 "ext2_update_dynamic_rev"。雖然
__FUNCTION__ 看起來類似於標準 C 中的 __FILE__,但實際上 __FUNCTION__
是被編譯器替換的,不象 __FILE__ 被前處理器替換。
內建函式
========
GNU C 提供了大量的內建函式,其中很多是標準 C 庫函式的內建版本,例如
memcpy,它們與對應的 C 庫函式功能相同,本文不討論這類函式,其他內建函式
的名字通常以 __builtin 開始。
* __builtin_return_address (LEVEL)
內建函式 __builtin_return_address 返回當前函式或其呼叫者的返回地址,引數
LEVEL 指定在棧上搜尋框架的個數,0 表示當前函式的返回地址,1 表示當前函式
的呼叫者的返回地址,依此類推。例如:
++++ kernel/sched.c
437: printk(KERN_ERR "schedule_timeout: wrong timeout "
438: "value %lx from %p ", timeout,
439: __builtin_return_address(0));
* __builtin_constant_p(EXP)
內建函式 __builtin_constant_p 用於判斷一個值是否為編譯時常數,如果引數
EXP 的值是常數,函式返回 1,否則返回 0。例如:
++++ include/asm-i386/bitops.h
249: #define test_bit(nr,addr)
250: (__builtin_constant_p(nr) ?
251: constant_test_bit((nr),(addr)) :
252: variable_test_bit((nr),(addr)))
很多計算或操作在引數為常數時有更最佳化的實現,在 GNU C 中用上面的方法可以
根據引數是否為常數,只編譯常數版本或非常數版本,這樣既不失通用性,又能在
引數是常數時編譯出最最佳化的程式碼。
* __builtin_expect(EXP, C)
內建函式 __builtin_expect 用於為編譯器提供分支預測資訊,其返回值是整數表
達式 EXP 的值,C 的值必須是編譯時常數。例如:
++++ include/linux/compiler.h
13: #define likely(x) __builtin_expect((x),1)
14: #define unlikely(x) __builtin_expect((x),0)
++++ kernel/sched.c
564: if (unlikely(in_interrupt())) {
565: printk("Scheduling in interrupt ");
566: BUG();
567: }
這個內建函式的語義是 EXP 的預期值是 C,編譯器可以根據這個資訊適當地重排
語句塊的順序,使程式在預期的情況下有更高的執行效率。上面的例子表示處於中
斷上下文是很少發生的,第 565-566 行的目標碼可能會放在較遠的位置,以保證
經常執行的目標碼更緊湊。
這些擴充套件對最佳化、目的碼佈局、更安全的檢查等方面提供了很強的支援。本文把
支援 GNU 擴充套件的 C 語言稱為 GNU C。
Linux 核心程式碼使用了大量的 GNU C 擴充套件,以至於能夠編譯 Linux 核心的唯一編
譯器是 GNU CC,以前甚至出現過編譯 Linux 核心要使用特殊的 GNU CC 版本的情
況。本文是對 Linux 核心使用的 GNU C 擴充套件的一個彙總,希望當你讀核心原始碼遇
到不理解的語法和語義時,能從本文找到一個初步的解答,更詳細的資訊可以檢視
gcc.info。文中的例子取自 Linux 2.4.18。
語句表示式
==========
GNU C 把包含在括號中的複合語句看做是一個表示式,稱為語句表示式,它可以出
現在任何允許表示式的地方,你可以在語句表示式中使用迴圈、區域性變數等,原本
只能在複合語句中使用。例如:
++++ include/linux/kernel.h
159: #define min_t(type,x,y)
160: ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
++++ net/ipv4/tcp_output.c
654: int full_space = min_t(int, tp->window_clamp, tcp_full_space(sk));
複合語句的最後一個語句應該是一個表示式,它的值將成為這個語句表示式的值。
這裡定義了一個安全的求最小值的宏,在標準 C 中,通常定義為:
#define min(x,y) ((x) < (y) ? (x) : (y))
這個定義計算 x 和 y 分別兩次,當引數有副作用時,將產生不正確的結果,使用
語句表示式只計算引數一次,避免了可能的錯誤。語句表示式通常用於宏定義。
Typeof
======
使用前一節定義的宏需要知道引數的型別,利用 typeof 可以定義更通用的宏,不
必事先知道引數的型別,例如:
++++ include/linux/kernel.h
141: #define min(x,y) ({
142: const typeof(x) _x = (x);
143: const typeof(y) _y = (y);
144: (void) (&_x == &_y);
145: _x < _y ? _x : _y; })
這裡 typeof(x) 表示 x 的值型別,第 142 行定義了一個與 x 型別相同的區域性變
量 _x 並初使化為 x,注意第 144 行的作用是檢查引數 x 和 y 的型別是否相同。
typeof 可以用在任何型別可以使用的地方,通常用於宏定義。
零長度陣列
==========
GNU C 允許使用零長度陣列,在定義變長物件的頭結構時,這個特性非常有用。例
如:
++++ include/linux/minix_fs.h
85: struct minix_dir_entry {
86: __u16 inode;
87: char name[0];
88: };
結構的最後一個元素定義為零長度陣列,它不佔結構的空間。在標準 C 中則需要
定義陣列長度為 1,分配時計算物件大小比較複雜。
可變引數宏
==========
在 GNU C 中,宏可以接受可變數目的引數,就象函式一樣,例如:
++++ include/linux/kernel.h
110: #define pr_debug(fmt,arg...)
111: printk(KERN_DEBUG fmt,##arg)
這裡 arg 表示其餘的引數,可以是零個或多個,這些引數以及引數之間的逗號構
成 arg 的值,在宏擴充套件時替換 arg,例如:
pr_debug("%s:%d",filename,line)
擴充套件為
printk("<7>" "%s:%d", filename, line)
使用 ## 的原因是處理 arg 不匹配任何引數的情況,這時 arg 的值為空,GNU
C 前處理器在這種特殊情況下,丟棄 ## 之前的逗號,這樣
pr_debug("success! ")
擴充套件為
printk("<7>" "success! ")
注意最後沒有逗號。
標號元素
========
標準 C 要求陣列或結構變數的初使化值必須以固定的順序出現,在 GNU C 中,通
過指定索引或結構域名,允許初始化值以任意順序出現。指定陣列索引的方法是在
初始化值前寫 '[INDEX] =',要指定一個範圍使用 '[FIRST ... LAST] =' 的形式,
例如:
+++++ arch/i386/kernel/irq.c
1079: static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
將陣列的所有元素初使化為 ~0UL,這可以看做是一種簡寫形式。
要指定結構元素,在元素值前寫 'FIELDNAME:',例如:
++++ fs/ext2/file.c
41: struct file_operations ext2_file_operations = {
42: llseek: generic_file_llseek,
43: read: generic_file_read,
44: write: generic_file_write,
45: ioctl: ext2_ioctl,
46: mmap: generic_file_mmap,
47: open: generic_file_open,
48: release: ext2_release_file,
49: fsync: ext2_sync_file,
50 };
將結構 ext2_file_operations 的元素 llseek 初始化為 generic_file_llseek,
元素 read 初始化為 genenric_file_read,依次類推。我覺得這是 GNU C 擴充套件中
最好的特性之一,當結構的定義變化以至元素的偏移改變時,這種初始化方法仍然
保證已知元素的正確性。對於未出現在初始化中的元素,其初值為 0。
Case 範圍
=========
GNU C 允許在一個 case 標號中指定一個連續範圍的值,例如:
++++ arch/i386/kernel/irq.c
1062: case '0' ... '9': c -= '0'; break;
1063: case 'a' ... 'f': c -= 'a'-10; break;
1064: case 'A' ... 'F': c -= 'A'-10; break;
case '0' ... '9':
相當於
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
宣告的特殊屬性
==============
GNU C 允許宣告函式、變數和型別的特殊屬性,以便手工的程式碼最佳化和更仔細的代
碼檢查。要指定一個宣告的屬性,在宣告後寫
__attribute__ (( ATTRIBUTE ))
其中 ATTRIBUTE 是屬性說明,多個屬性以逗號分隔。GNU C 支援十幾個屬性,這
裡介紹最常用的:
* noreturn
屬性 noreturn 用於函式,表示該函式從不返回。這可以讓編譯器生成稍微最佳化的
程式碼,最重要的是可以消除不必要的警告資訊比如未初使化的變數。例如:
++++ include/linux/kernel.h
47: # define ATTRIB_NORET __attribute__((noreturn)) ....
61: asmlinkage NORET_TYPE void do_exit(long error_code)
ATTRIB_NORET;
* format (ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)
屬性 format 用於函式,表示該函式使用 printf, scanf 或 strftime 風格的參
數,使用這類函式最容易犯的錯誤是格式串與引數不匹配,指定 format 屬性可以
讓編譯器根據格式串檢查引數型別。例如:
++++ include/linux/kernel.h?
89: asmlinkage int printk(const char * fmt, ...)
90: __attribute__ ((format (printf, 1, 2)));
表示第一個引數是格式串,從第二個引數起根據格式串檢查引數。
* unused
屬性 unused 用於函式和變數,表示該函式或變數可能不使用,這個屬性可以避免
編譯器產生警告資訊。
* 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 的用途大多是定義硬體相關的結
構,使元素之間沒有因對齊而造成的空洞。
當前函式名
==========
GNU CC 預定義了兩個標誌符儲存當前函式的名字,__FUNCTION__ 儲存函式在原始碼
中的名字,__PRETTY_FUNCTION__ 儲存帶語言特色的名字。在 C 函式中,這兩個
名字是相同的,在 C++ 函式中,__PRETTY_FUNCTION__ 包括函式返回型別等額外
資訊,Linux 核心只使用了 __FUNCTION__。
++++ fs/ext2/super.c
98: void ext2_update_dynamic_rev(struct super_block *sb)
99: {
100: struct ext2_super_block *es = EXT2_SB(sb)->s_es;
101:
102: if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
103: return;
104:
105: ext2_warning(sb, __FUNCTION__,
106: "updating to rev %d because of new feature flag, "
107: "running e2fsck is recommended",
108: EXT2_DYNAMIC_REV);
這裡 __FUNCTION__ 將被替換為字串 "ext2_update_dynamic_rev"。雖然
__FUNCTION__ 看起來類似於標準 C 中的 __FILE__,但實際上 __FUNCTION__
是被編譯器替換的,不象 __FILE__ 被前處理器替換。
內建函式
========
GNU C 提供了大量的內建函式,其中很多是標準 C 庫函式的內建版本,例如
memcpy,它們與對應的 C 庫函式功能相同,本文不討論這類函式,其他內建函式
的名字通常以 __builtin 開始。
* __builtin_return_address (LEVEL)
內建函式 __builtin_return_address 返回當前函式或其呼叫者的返回地址,引數
LEVEL 指定在棧上搜尋框架的個數,0 表示當前函式的返回地址,1 表示當前函式
的呼叫者的返回地址,依此類推。例如:
++++ kernel/sched.c
437: printk(KERN_ERR "schedule_timeout: wrong timeout "
438: "value %lx from %p ", timeout,
439: __builtin_return_address(0));
* __builtin_constant_p(EXP)
內建函式 __builtin_constant_p 用於判斷一個值是否為編譯時常數,如果引數
EXP 的值是常數,函式返回 1,否則返回 0。例如:
++++ include/asm-i386/bitops.h
249: #define test_bit(nr,addr)
250: (__builtin_constant_p(nr) ?
251: constant_test_bit((nr),(addr)) :
252: variable_test_bit((nr),(addr)))
很多計算或操作在引數為常數時有更最佳化的實現,在 GNU C 中用上面的方法可以
根據引數是否為常數,只編譯常數版本或非常數版本,這樣既不失通用性,又能在
引數是常數時編譯出最最佳化的程式碼。
* __builtin_expect(EXP, C)
內建函式 __builtin_expect 用於為編譯器提供分支預測資訊,其返回值是整數表
達式 EXP 的值,C 的值必須是編譯時常數。例如:
++++ include/linux/compiler.h
13: #define likely(x) __builtin_expect((x),1)
14: #define unlikely(x) __builtin_expect((x),0)
++++ kernel/sched.c
564: if (unlikely(in_interrupt())) {
565: printk("Scheduling in interrupt ");
566: BUG();
567: }
這個內建函式的語義是 EXP 的預期值是 C,編譯器可以根據這個資訊適當地重排
語句塊的順序,使程式在預期的情況下有更高的執行效率。上面的例子表示處於中
斷上下文是很少發生的,第 565-566 行的目標碼可能會放在較遠的位置,以保證
經常執行的目標碼更緊湊。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617542/viewspace-947295/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- GNUC擴充套件:Linux作業系統的核心使用(轉)套件Linux作業系統
- gcc核心擴充套件linuxforum(轉)GC套件Linux
- C# 擴充套件方法 借籤於 Objective-C 擴充套件類.C#套件Object
- C#基礎系列:擴充套件方法的使用C#套件
- 擴充套件你的STRUTS (轉)套件
- 轉摘_如何使linux擴充套件使用 大記憶體Linux套件記憶體
- C++ 對C的擴充套件有哪些C++套件
- C 擴充套件庫 – mysql API套件MySqlAPI
- C#.NET擴充套件方法C#套件
- 知識庫(2)-使用Windows OpenGL擴充套件機制來訪問OpenGL擴充套件 (轉)Windows套件
- PDF 擴充套件包使用套件
- kotlin 擴充套件(擴充套件函式和擴充套件屬性)Kotlin套件函式
- Solon詳解(六)- Solon的校驗擴充套件框架使用與擴充套件套件框架
- STL中的棧的擴充套件 (轉)套件
- 使用Kotlin擴充套件函式擴充套件Spring Data案例Kotlin套件函式Spring
- php mysqli擴充套件庫的使用PHPMySql套件
- OpenGL 1.3 最新擴充套件 (轉)套件
- C#中的擴充套件類的理解C#套件
- linux下php實現C/C++擴充套件程式設計LinuxPHPC++套件程式設計
- c盤擴充套件卷選項是灰的怎麼辦 c盤不能擴充套件卷的辦法套件
- (PHP7核心剖析-11) 模組擴充套件PHP套件
- 聊聊Dubbo(五):核心原始碼-SPI擴充套件原始碼套件
- HybridDBforPostgreSQL(Greenplum)有哪些核心擴充套件SQL套件
- 使用C++為node.js寫擴充套件模組C++Node.js套件
- C++使用ffpython嵌入和擴充套件pythonC++Python套件
- php新增pcntl擴充套件(Linux)PHP套件Linux
- 擴充套件Linux網路棧套件Linux
- Linux擴充套件邏輯卷Linux套件
- 使用 Rust 建立 PHP 擴充套件RustPHP套件
- 谷歌的三大可擴充套件核心架構谷歌套件架構
- C++對C語言的擴充套件(1)--引用C++C語言套件
- 使用 Cython 為 Python 編寫更快的 C 擴充套件Python套件
- 在 Linux 下使用 fdisk 擴充套件分割槽容量Linux套件
- WCF擴充套件:行為擴充套件Behavior Extension套件
- Flutter——Dart Extension擴充套件方法的使用FlutterDart套件
- linux下線上擴大擴充套件分割槽的方法Linux套件
- ?用Chrome擴充套件管理器, 管理你的擴充套件Chrome套件
- c# ExpandoObject動態擴充套件物件C#Object套件物件