- 局部變數
- 過時守則 : 32bit CPU上,不要使用char當作區域變數,要改用unsigned int
int checksum_v1 (int *data) {
char i;
int sum = 0;
for (i=0; i<64; i++) {
sum +=data[i];
}
return sum;
}
int checksum_v2 (int *data) {
unsigned int i;
int sum = 0;
for (i=0; i<64; i++) {
sum +=data[i];
}
return sum;
}
register寬度為32bit。如果變數是char,編譯器反而要register跟 0xFF 做mask,這樣才能保證不會溢位。且unsigned可以熱
實驗結果:
checksum_v1()和checksum_v2() 並沒差,不需要改變。
- 守則 : 不能把 int加法的值存在short內,即便知道 short不會overflow
short checksum_v3 (int *data) {
unsigned int i;
short sum = 0;
for (i=0; i<64; i++) {
sum = (short) ( sum +data[i]);
}
return sum;
}
short checksum_v4 (short *data) {
unsigned int i;
int sum = 0;
for (i=0; i <64; i++) {
sum += *(data ++);
}
return (short) sum;
}
理由 :
compiler會多花幾個arm 指令把值塞入 short內
實驗結果:
在checksum_v3() 的迴圈內會多花一個指令 (uxth - zero extend halfword. Extend 16-bit value to 32-bit value)去把short先變成 int。離開迴圈後,再用另一個指令 (sxth - sign extend halfword) 去把 int變為short。
- 守則 : 使用除法時,盡量使用無符號數
- 守則 : 使用除法時,盡量使用無符號數
int average_v1 ( int a, int b) {
return (a+b) /2;
}
理由:
對負數除二時,需要先加一然後再往右shift一位。ex: -3/2 = -1 然而 -3 >> 1 = -2,所以需要先加一然後再移位。
實驗結果:
依然有效
- C迴圈結構
- 過時守則 : For Loop內要使用index時,要用遞減方式
- 過時守則 : For Loop內要使用index時,要用遞減方式
int checksum_v5 (int *data) {
unsigned int i;
int sum = 0;
for ( i = 0; i< 64;i++) {
sum += *(data++);
}
return sum;
}
int checksum_v6 (int *data) {
unsigned int i;
int sum = 0;
for( i=64; i!=0; i--) {
sum+=*(data++);
}
return sum;
}
理由 :
當時的GCC會多花一個指令處理遞增For Loop的index 。
實驗結果 :
不需使用遞減方式,現在的GCC已經最佳化了,不需要考慮這個。
- 守則 : 使用 do {} while ()替代 for loop
int checksum_v7 (int *data, unsigned int N) {
int sum;
for(; N!=0; N--) {
sum += *(data++);
}
return sum;
}
int checksum_v8 (int *data, unsigned int N) {
int sum;
do {
sum += *(data++);
} while( --N !=0);
return sum;
}
理由 :
For Loop在第一次迴圈時,會檢查index N是否為 0,但是通常N 不為 0,所以會多花一個arm 指令。
實驗結果 :
仍然有效
- 迴圈展開
- 守則 : 把迴圈內的內容展開,如此可以減少判斷終止的次數
int checksum_v9 (int *data, unsigned int N ) {
int sum = 0;
do {
sum += *(data++);
sum += *(data++);
sum += *(data++);
sum += *(data++);
N -= 4;
} while (N != 0);
return sum;
}
理由 :
當迴圈的指令數很少時,判斷中止條件的指令就佔很大的比例。將迴圈的內容展開,可以稀釋中止條件所佔的比例。
實驗結果 :
仍然有效
- 守則 : 把迴圈內的內容展開,如此可以減少判斷終止的次數
int checksum_v9 (int *data, unsigned int N ) {
int sum = 0;
do {
sum += *(data++);
sum += *(data++);
sum += *(data++);
sum += *(data++);
N -= 4;
} while (N != 0);
return sum;
}