一位讀者來信來電問 C 程式的問題
2009/07/11 13:03
瀏覽1,694
迴響0
推薦2
引用0
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 int uint16_t;
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;
}
筆者的回答如下:
#include
#include
#include
#include
#include
//#include
typedef int uint16_t;
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
這位讀者所附的程式如下:
#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 時又蓋到自己」。
筆者略微增修幾行程式 (以紅色顯示),即可證明這支程式在「將 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)
最後,筆者想說的是
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)
最後,筆者想說的是
晚上十點過後還打電話是不太禮貌的行為,要稍微留意一下!
你可能會有興趣的文章:









