makefile及C进阶

Makefile

001_Makefile的引入及规则
使用keil, mdk, avr等工具开发程序时点点鼠标就可以编译了,
它的内部机制是什么?它怎么组织管理程序?怎么决定编译哪一个文件?

gcc -o test a.c b.c
// 简单,
// 但是会对所有文件都处理一次,
// 文件多时如果只修改其中一个文件会导致效率低

Makefile的核心—规则 :

目标 : 依赖1 依赖2 …
[TAB]命令
当"目标文件"不存在, 或某个依赖文件比目标文件"新",则: 执行"命令"

002_Makefile的语法
a. 通配符: %.o
$@ 表示目标
$< 表示第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[];
}
//------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/weixin_42068537/article/details/84111395