2008年3月20日 星期四

一種奇怪的 C 寫法

在 Porting ARM Linux for NO MMU system 時, 遇到一個奇怪的寫法, 在 binfmt_flat.c 之中的 load_flat_binary() 函式之中, 有一段 code:


#include &lt include &gt
int main(int argc, char **argv)
{
char j;
int k;
int q[10]={1,2,3,4,5,6,7,8,9,10};
int *p= (int*) q[5];

for(j=0;j<3;j++) {
k = (j)[(unsigned int*) &q[5]];
printf("k is %d\n",k);
}

}


它的輸出是:

black@black2:~/workarea$ ./a.out

k is 6
k is 7
k is 8

如果我把

k = (j)[(unsigned int*) &q[5]];

改成

k = (j)[(unsigned char*) &q[5]];

則輸出會是 6,0,0, 若改成 unsigned short, 則輸出會是 6,0,7!

但是我改變 j 的型態為 char, short, long 都不會有影響!!

事實上, 一個陣列名稱不過是代表某個位址的 symbol, 因此, 它的元素的位址本來就是

symbol address + index*element_size

所以也許我們可以把 j 看成一個變動的 symbol address!! 於是我作個實驗, 把 [ ] 中的指標拿掉, 結果出現錯誤:

error: subscripted value is neither array nor pointer


C 似乎期待在中間一定要有一個 pointer 或 arrary!! 事實上, 在 C 中 array 和 pointer 本來也是互相為用!!

從以上結果可以推論: 它的位址計算方式, 是 ( (unsigned char*) &q[5] + j), 如果你是 unsigned char 的話!! 我們再作一次實驗:

#include

int main(int argc, char **argv)
{
short j;
int k;
int l;

int q[10]={1,2,3,4,5,6,7,8,9,10};
int *p= (int*) q[5];

for(j=0;j<3;j++) {
k = (j)[(unsigned char *) &q[5]];
printf("k is %d\n",k);
l = ((unsigned char *) &q[5])[j];
printf("l is %d\n",l);
}
}

在此的 k 和 l 會得到完全相同的值!!

因此, 我們可以說: (j)[(unsigned char*) &q[5]] 幾乎就是 ((unsigned char*) &q[5])[j]!!

當然, 行文至此, 我只是用實驗的方式知道段程式的行為, 但仍不知那一條規則容許它這樣寫? 這有待高手替我解答了!!

我也不了解這位老兄為什麼用 (j)[(unsigned char*) &q[5]] 而不用 ((unsigned char*) &q[5])[j], 也許有我不知道的秘密也說不定!!

沒有留言:

佇 Linux 來看GPX 檔案

最近定定有戶外活動。使用𤆬路機 (GPS) 來記錄行過的路線。普通我記錄路線,攏是用手機仔抑是專門个𤆬路機,罕得用電腦來看。 毋過,"仙人拍鼓有時錯,跤步踏差啥人無"。有一擺我無細膩,袂記得共一擺活動的路線收煞起來,閣直接開始記錄下一擺的活動,按呢共幾落...