1. 程式人生 > >makefile及C進階

makefile及C進階

Makefile

001_Makefile的引入及規則
使用keil, mdk, avr等工具開發程式時點點滑鼠就可以編譯了,
它的內部機制是什麼?它怎麼組織管理程式?怎麼決定編譯哪一個檔案?

gcc -o test a.c b.c
// 簡單,
// 但是會對所有檔案都處理一次,
// 檔案多時如果只修改其中一個檔案會導致效率低

Makefile的核心—規則 :

目標 : 依賴1 依賴2 …
[TAB]命令
當"目標檔案"不存在, 或某個依賴檔案比目標檔案"新",則: 執行"命令"

002_Makefile的語法
a. 萬用字元: %.o
[email protected]

表示目標
$< 表示第1個依賴檔案
$^ 表示所有依賴檔案

b. 假想目標: .PHONY

c. 即時變數、延時變數, export
簡單變數(即時變數) :
A := xxx # A的值即刻確定,在定義時即確定
B = xxx # B的值使用到時才確定

:= # 即時變數
= # 延時變數
?= # 延時變數, 如果是第1次定義才起效, 如果在前面該變數已定義則忽略這句
+= # 附加, 它是即時變數還是延時變數取決於前面的定義

參考文件:
a. 百度搜 “gnu make 於鳳昌”
b. 官方文件: http://www.gnu.org/software/make/manual/

003_Makefile函式
a. $(foreach var,list,text)
b. $(filter pattern…,text) # 在text中取出符合patten格式的值
$(filter-out pattern…,text) # 在text中取出不符合patten格式的值

c. $(wildcard pattern) # pattern定義了檔名的格式,
# wildcard取出其中存在的檔案
d. ( p a

t s u b s t p a t t e r n , r e p l a c e m e n t , (patsubst pattern,replacement, (var)) # 從列表中取出每一個值
# 如果符合pattern
# 則替換為replacement

004_Makefile例項
a. 改進: 支援標頭檔案依賴

gcc -M c.c // 打印出依賴

gcc -M -MF c.d c.c // 把依賴寫入檔案c.d

gcc -c -o c.o c.c -MD -MF c.d // 編譯c.o, 把依賴寫入檔案c.d

b. 新增CFLAGS
c. 分析裸板Makefile
//---------------------------------------------
型別轉換:
char c = 0;
short s = c;
int b = s;都安全
char;short;int ;unsigned int;long;unsigned long;flaot;double;
強制型別和隱式型別轉換。
//--------------------------
變數屬性:
auto表明將被修飾的變數儲存與棧上
register關鍵字指明將區域性變數儲存於暫存器中,不能用&獲取該變數地址
register不能宣告全域性變數;提高執行效率。
static修飾的區域性變數儲存在程式靜態區。
static修飾的全域性變數作用域只是宣告的檔案中;
static修飾的函式作用域只是宣告的檔案中;
例:

int f1()
{
   int r = 0;
   r++;
   return r;
}
int f2()
{
  static int r = 0;  
  r++;
  return r;
}
int main ()
{
  auto int i = 0;    //顯示宣告 auto 屬性,i為棧變數
  static int k = 0;  //區域性變數k的儲存區位於靜態區,作用域位於main中
  register int j = 0; //向編譯器申請將j儲存與暫存器中
  printf("%p\n",&i);
  printf("%p\n",&k);
  for (i=0;i<5;i++)
    {
	  printf("%d\n",f1());
	}
   for (i=0;i<5;i++)
     {
	   printf("&d\n",f2());
	 }  
   return 0;	 
}

結果:11111與12345.
//---------------------------------
extern:能夠指示編譯器按照標準c方式編譯程式。
test.c
extern int g_i;
int main ()
{
printf("%d\n",g_i);
}
int g_i;編譯成功。
g.c:
static int g_i。即便一起編譯兩個檔案也會出錯。static將變數使用範圍縮小,只能在本模組。
//-----------------------------------------
分支語句:例列印10內奇數。

void f1(int n)
{
  int i = 0;
  for(i=1;i<=n;i++)
    {
	  if ((i % 2)== 0)
	   {
	     break;
	   }
	printf("%d",i);
	}
	printf("\n");
}
void f2(int n)
{
  int i = 0;
  for (i=1;i<=n;i++)
  {
    if((i % 2)== 0)
	  {
	    continue;
	  }
    printf("%d\n",i);
  }
    printf("\n");
}
int main()
{
  f1(10);
  f2(10);
  return 0;
}

輸出結果為:1;13579;

//---------------------
do while ,break可用於避免記憶體洩漏
const修飾的變數是隻讀的,本質還是變數
const修飾的區域性變數在棧上分配空間
const修飾的全域性變數在全域性資料區分配空間
const只在編譯期有用,在執行期無用
const修飾的變數不是真的常量,它只是告訴編譯器該變數不能出現在賦值符號的左邊。
const不能定義真正意義上的常量
volatile: const volatile int i=0;

union判斷系統大小端;
int i =1;0x01 0x00 0x00 0x00此為小端模式–>高地址,低位元組低地址
int i =1;0x00 0x00 0x00 0x01此為大端模式–>高地址,高位元組低地址
例:

int system_mode()
{
   union SM
    {
     int i;
     char c;
    };
	union SM sm;
	sm.i = 1;
	return sm.c;
}

int main ()
{
  printf("system_mode:%d\n",system_mode());
  return 0;
}

結果:1小端模式。
union中所有成員共享同一個儲存空間,最大成員的空間;
struct柔性陣列:
strut softarray
{
int len;
int array[];
}
//------------------------------------------------------