1. 程式人生 > >keil c51編譯器的一些使用心得(一)

keil c51編譯器的一些使用心得(一)

    本人是剛剛參加工作的學生,使用keil編譯器已經半年多了,在這半年的時間裡,我總結了keil的使用的一些心得,希望和大家分享一下,另外請高人點撥一下,由於我不是計算機專業的,所以對於編譯原理和作業系統等高深的課程沒有接觸過,總是認為以下提到的一些規律都是有理論根據的,希望高人指點。
    現在的儲存器已經不像七八年前那樣昂貴了,但是ram相對於rom和eeprom的價格還是不可同樣看待的,所以程式中節省記憶體在現在看來還是非常關鍵的。原因有以下幾點:
1.ram的存取速度相對於eeprom的存取速度要快很多倍,不在一個數量級上,主要是因為eeprom的儲存要想寫入就必須先擦除,而且eeprom的擦出需要成塊擦除(這是由於eeprom的擦除原理是場效電晶體的柵極上電擦除的,為了節省成本廠家一般都是8Bytes/page 64Bytes/page),所以使用ram來處理中間的資料是能夠符合速度要求的。
2.無論是xram還是eeprom都是外部儲存器,在負值時都要用到16bit地址空間(8位機),這樣無形中就增大了程式的code的體積並且使得速度上也受到影響,所以儘量把indata區的ram用到極限是非常有意義的。

本人總結了一些節省記憶體的規律,提供給大家討論一下,看看是否可行。

1.記憶體分配的基本原理:
keil與其他的c語言編譯器我認為從記憶體分配的原理上是基本相同的。總結起來,其實很簡單,就是選最長的路徑進行編譯(話糙理不糙),例如下面的兩段程式
program 1:
unsigned char a();
void b();
void main()
{
 unsigned char byte1;
 unsigned char byte2;

 byte1 = byte2 = 3;

 if( a() == 3)
 {
  b();
 }

 a();

 return;
}

// a function
unsigned char a()
{
 unsigned char byte_a1;
 unsigned char byte_a2;

 byte_a1 = byte_a2 = 3;

 byte_a1 = 4;
 byte_a2 = 5;

 return byte_a1;
}

// b function
void b()
{
 unsigned char byte_b1;
 unsigned char byte_b2;
 unsigned char byte_b3;

 byte_b1 = byte_b2 = byte_b3 = 3;

 return;
}

program 2:
void a();
void b();
void main()
{
 unsigned char byte1;
 unsigned char byte2;

 byte1 = byte2 = 3;

 a();

 return;
}

// a function
void a()
{
 unsigned char byte_a1;
 unsigned char byte_a2;

 byte_a1 = byte_a2 = 3;

 if (byte_a1 == 3)
 {
  b();
 }

 byte_a1 = 4;
 byte_a2 = 5;

 return;
}

// b function
void b()
{
 unsigned char byte_b1;
 unsigned char byte_b2;
 unsigned char byte_b3;

 byte_b1 = byte_b2 = byte_b3 = 3;

 return;
}

兩段程式的作用是相同的,都是先執行函式a,然後根據byte_a1的值判斷去執行b程式,但是用keil編譯的結果卻不相同program 1 編譯的結果是data:14 code:48,而program 2 編譯的結果是data:16 code:56,可見program 1 比 program 2 即節省了code又節省了記憶體。

看一下反彙編程式碼,就可以瞭解原因了,在a函式中呼叫b函式,a函式定義的byte_a1和byte_a2變數沒有被釋放,所以program 2 的記憶體分配是 8(SFR) + 1(STACK) + 2(MAIN FUNC) + 2(A FUNC) + 3(B FUNC) = 16 Bytes,而program 1 的記憶體分配是 8(SFR) + 1(STACK) + 3(B FUNC) = 14Bytes, 由於B函式和A函式是並行的,所以節省了a函式需要的2個位元組。

這樣總結看來程式不要序列,應儘量並行,充分利用有限的ram資源,這樣既可以使code區變小,也可以使速度變快。

2.uncalled segment 影響記憶體分配:
不知道大家是否發現過當存在沒有呼叫的函式時,記憶體空間很有可能會溢位,這個原因其實也非常簡單例如:
program 3:
void a();
void b();
void c(unsigned char byte_input);
void main()
{
 unsigned char byte1;
 unsigned char byte2;

 byte1 = byte2 = 3;

 a();

 c(3);

 return;
}

// a function
void a()
{
 unsigned char byte_a1;
 unsigned char byte_a2;

 byte_a1 = byte_a2 = 3;

 if (byte_a1 == 3)
 {
  b();
 }

 byte_a1 = 4;
 byte_a2 = 5;

 return;
}

// b function
void b()
{
 unsigned char byte_b1;
 unsigned char byte_b2;
 unsigned char byte_b3;

 byte_b1 = byte_b2 = byte_b3 = 3;

 return;
}

void c(unsigned char byte_input)
{
 unsigned char byte_c;

 byte_c = byte_input;

 return;
}

program 3 所示如果再main.c裡面呼叫c(3)編譯後data:16,而如果不呼叫c(3),編譯後data:17,原因是呼叫c(3) data = 8(SFR) + 1(STACK) + 2(MAIN FUNC) + 2(A FUNC) + 3(B FUNC) = 16Bytes,而如果不呼叫c(3) data = 8(SFR) + 1(STACK) + 2(MAIN FUNC) + 2(A FUNC) + 3(B FUNC) + 1(C FUNC) = 17 Bytes。
所以,建議大家如果暫時不呼叫的函式最好遮蔽掉,以免影響整體的記憶體分配。

這次先寫到這裡吧,希望大家多和我討論討論,下一次我想和大家討論一下有關keil中data_group的問題。