字體:小 中 大 | |
|
|
2009/07/11 13:03:51瀏覽1647|回應0|推薦2 | |
2009 年 7 月 10 日晚上十一點,工作室的電話響了,筆者正納悶是誰這麼晚了還打電話,接了電話後才知道是一位讀者來電問一道 C 程式的問題 (e-mail 的寄發時間是當天的晚上六點)。他的問題如下: 你好 我跟你買過書,我買那一本C語言的修練與實踐,我有一個程式的問題想請教你一下。 這一個我所附上的範例,我有各問題。 很困惑? 是這樣的我宣告一個buf 4k 但試我卻塞給他64k 的資料,我根據你的書上第四章所講的 我有點疑惑。 我那個buf 宣告成不同的型態和放置的位置所的到的結果都不一樣。
我分別宣告 buf 為 char buf [4096] static char buf [4096] 以上兩個我都宣告在 main 我另一個宣告是放在 gloable放在main 上面。 我所知知道的事 宣告在main 裡面的變數 char buf[4096 ] 會規劃在 stack 那邊,我只要一run 就馬上 segmentation fault 我宣告成static char buf[4096] 會規劃在data area 但是run 起來不會出錯 我宣告在gloable 時buf 會規劃在bss 那邊 run 起來也不會出錯
我明明宣告一個4k 的資料但是卻塞進去64k 資料,但是當我宣告buf 在不同的位置時確有不一樣的答案 請問一下,這要如何解釋呢? 謝謝你
這位讀者所附的程式如下: #include <stdio.lh> #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> //#include <mem.h> typedef unsigned char uint8_t; typedef unsigned long uint32_t; unsigned char data[64 *1024]; int memcpy4(char *dst, unsigned char *src, int size); char testbuf[2] = {0x01, 0x05}; char buf[4096]= {0}; int main(){ long i = 0, test = 0; //static char buf[4096]= {0}; //char buf[4096]= {0}; //char testbuf[2] = {0x01, 0x05}; for(test = 0; test < testbuf[1]; test++){ printf("test is %ld\n",test); printf("testbuf[0] is %x\n",testbuf[0]); printf("testbuf[1] is %x\n",testbuf[1]); } for(i = 0; i < (1024 * 64); i++){ data[i] = i; //printf(" data[%ld] is %ld\n",i, (long)data[i]); } memcpy4(buf, data, 65536); printf(" Finish\n"); #if 0 for(test = 0; test < testbuf[1]; test++){ printf("2222 test is %ld\n",test); printf("2222 testbuf[0] is %x\n",testbuf[0]); printf("2222 testbuf[1] is %x\n",testbuf[1]); } #endif return 0; } int memcpy4(char *dst, unsigned char *src, int size) { long *ls = (long *)src; uint32_t data; for(; size >= 4; size-=4, ls++, dst+=4) { //printf("3333333333 size is %d\n",size); data = *ls; memcpy(dst, &data, sizeof(long)); } if (size) { data = *ls; printf("4444444444444444444444444444\n"); memcpy(dst, &data, size); } return 0; } 筆者的回答如下: 4K buf 在前,64K data 在後,將 64K data 內容拷貝至 4K buf 時又蓋到自己(64K data array)。至於為什麼不會發生 segmentation fault, 因為這些位址都已經分配給這支程式,是這支程式合法取得的記憶體資源,只是這支程式的邏輯在做拷貝時又不小心地蓋到自己,即 Source。 筆者略微增修幾行程式 (以紅色顯示),即可證明這支程式在「將 64K data 內容拷貝至 4K buf 時又蓋到自己」。 #include #include #include #include //#include typedef unsigned char uint8_t; typedef unsigned long uint32_t; unsigned char data[64 *1024]; int memcpy4(char *dst, unsigned char *src, int size); char testbuf[2] = {0x01, 0x05}; char buf[4096]= {0}; int main(){ long i = 0, test = 0; //static char buf[4096]= {0}; //char buf[4096]= {0}; //char testbuf[2] = {0x01, 0x05}; for(test = 0; test < testbuf[1]; test++){ printf("test is %ld\n",test); printf("testbuf[0] is %x\n",testbuf[0]); printf("testbuf[1] is %x\n",testbuf[1]); } for(i = 0; i < (1024 * 64); i++){ data[i] = i; //printf(" data[%ld] is %ld\n",i, (long)data[i]); } printf("data[0] = %d, data[1] = %d, data[2] = %d\n", data[0], data[1], data[2]); printf("&buf = %p, &data = %p\n", buf, data); memcpy4(buf, data, 65536); printf(" Finish\n"); printf("data[0] = %d, data[1] = %d, data[2] = %d\n", data[0], data[1], data[2]); #if 0 for(test = 0; test < testbuf[1]; test++){ printf("2222 test is %ld\n",test); printf("2222 testbuf[0] is %x\n",testbuf[0]); printf("2222 testbuf[1] is %x\n",testbuf[1]); } #endif return 0; } int memcpy4(char *dst, unsigned char *src, int size) { long *ls = (long *)src; uint32_t data; for(; size >= 4; size-=4, ls++, dst+=4) { //printf("3333333333 size is %d\n",size); //data = *ls; data = 0xffffffff; memcpy(dst, &data, sizeof(long)); } if (size) { data = *ls; printf("4444444444444444444444444444\n"); memcpy(dst, &data, size); } return 0; } 執行結果如下: test is 0 testbuf[0] is 1 testbuf[1] is 5 test is 1 testbuf[0] is 1 testbuf[1] is 5 test is 2 testbuf[0] is 1 testbuf[1] is 5 test is 3 testbuf[0] is 1 testbuf[1] is 5 test is 4 testbuf[0] is 1 testbuf[1] is 5 data[0] = 0, data[1] = 1, data[2] = 2 &buf = 20d20, &data = 21d28 Finish data[0] = 255, data[1] = 255, data[2] = 255 這支程式有一些值得討論與改進的地方: 1. data 被宣告成 unsigned char,而 for loop 的邏輯是 for (i = 0; i < 1024 * 64; i++) data[i] = i; 事實上,data[i] 的值只可能介於 [0, 255],筆者有點不瞭解此處的意圖為何。 2. 有一些不必要的 type cast 與 assignment,例如 memcpy4 中的 long *ls = (long *)src; 與 data = *ls; 其實原程式可以直接寫成 memcpy((void*)dst, (void*)src, sizeof(long)); 3. 原程式使用了太多的 magic number (即寫死的常數值 ... constants, literals) 最後,筆者想說的是 晚上十點過後還打電話是不太禮貌的行為,要稍微留意一下! |
|
( 創作|其他 ) |