概览
项目地址
https://github.com/impact-eintr/LinuxC
c的历史
- 1960 原型A语言->ALGOL语言
- 1963 CPL语言
- 1967 BCPL
- 1970 B语言
- 1973 C语言
C语言特点
- 基础性语言
- 语法简洁 紧凑 方便 灵活(得益于指针)
- 运算符 数据结构丰富
- 结构化 模块化编程
- 移植性好 执行效率高
- 允许直接对硬件操作
学习建议
- 概念的正确性
- 动手能力
- 主动阅读优秀的程序段
- 大量练习,编程是技术不是理论
学习思路
- 基本概念
- 数据类型 运算符 表达式
- 输入输出
- 流程控制
- 数组
- 指针
- 函数
- 构造类型
- 动态内存管理
- 常用库函数
- 调试工具和调试技巧
环境搭建与"Hello world"
环境
- 当前测试环境是安装了基于
archlinux 的manjarolinux 发行版的物理机,大家自己搭建linux环境的话推荐试用或租用云服务器或者尝试WSL gcc 版本是 10.2.0- 编辑器使用
vim (推荐vim配置vimplus)
“Hello world”
#inlcude <stdio.h>
#include <stdlib.h>
int main(void){
printf("hello world\n");
exit(0);
}
gcc 编译c的源文件过程
gcc -v
C源文件->预处理->编译->汇编->链接->可执行文件
完整过程
gcc -E hello.c > hello.i
gcc -S hello.i
gcc -c hello.s
gcc hello.o -o hello
或者
gcc hello.c -o hello
又或者
make hello
执行
./hello
hello world
基本概念
怎么写代码
头文件的重要性
在c中,如果没有出现函数原型,就默认函数的返回值是int
#include <stdio.h>
int main()
{
<<<<<<< HEAD
int *num = malloc(sizeof(int));
*num = 100;
printf("%d\n",*num);
=======
int *num = (int *)malloc(sizeof(int));
>>>>>>> d8201497ccb6ce60411ef4f1d6347921a54e7c22
return 0;
}
hello.c: 在函数‘main’中:
hello.c:5:23: 警告:隐式声明函数‘malloc’ [-Wimplicit-function-declaration]
5 | int *num = (int *)malloc(sizeof(int));
| ^~~~~~
hello.c:5:23: 警告:隐式声明与内建函数‘malloc’不兼容
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *num = (int *)malloc(sizeof(int));
return 0;
}
数据类型 运算符 表达式
- 基本类型
- 构造类型
- 数组
- 结构体 struct
- 共用体 union
- 枚举类型 enum
- 指针类型
- 空类型 void
254 -> unsigned int -> 32bit
(254)10 = (1111 1110)2 = (376)8 = (FE)16
254
B11111110(c不认识这个表示)
0376
0xFE
类型转换
int i;
float f;
doubel d;
char ch;
ch + i -> i
f -d -> d
(ch + i) - (dloat -double) -> double
bool
#incldue <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main() {
bool a = false;
printf("a = %d\n", a);
exit(0);
}
浮点型的失真问题
int func(float f) {
if (f < 0) {
return -1;
} else if (fabs(f-0) <= 1e-6) {
return 0;
} else {
return 1;
}
}
char
在iso c中 char 有无符号是未定义行为
0
0(整形) '0'(字符常量) "0"(字符串常量) '\0'(字符常量)
输入输出
数据类型要和后续代码中所使用的输入输出要相匹配(小心自相矛盾)
#include <stdlib.h>
#include <stdio.h>
int main() {
unsigned int a;
a = 1 << 31;
printf("%d", a);
}
正确
#include <stdlib.h>
#include <stdio.h>
int main() {
unsigned int a;
a = 1 << 31;
printf("%ud", a);
}
常量与变量
常量
- 整形常量 1 890
- 实型常量 1.2 3.14
- 字符常量 ‘\t’ ‘\n’ ‘\0’ ‘\015’(8进制) ‘\x7f’ ‘\018’(错误的表示!!)
- 字符串常量 “” “a” “abXYZ” “abc\n\021\010”(a b c \n \021 \0 1 8)
- 标识常量
宏的用法
#include <stdlib.h>
#include <stdio.h>
#define PI 3.1415926
#define ADD 2+3
// 正确写法
//#define ADD (2+3)
int main() {
printf("%f\n", PI);
printf("%d\n", ADD * ADD);
}
# 6 "pi.c"
int main() {
printf("%f\n", 3.1415926);
printf("%d\n", 2+3 * 2+3);
}
#include <stdlib.h>
#include <stdio.h>
#define MAX(a,b) ({int A=a,B=b; ((A) > (B) ? (A) : (B));})
int main() {
int a = 3, b = 5;
printf("%d\n",MAX(a++, b++));
printf("%d\n",MAX(a++, b++));
}
#include <stdlib.h>
#include <stdio.h>
#define MAX(a,b) ({typeof(a) A=a,B=b; ((A) > (B) ? (A) : (B));})
int main() {
int a = 3, b = 5;
printf("%d\n",MAX(a++, b++));
printf("%d\n",MAX(a++, b++));
}
在程序的预处理阶段,占编译时间,不占运行时间(没有函数调用的消耗),但不检查语法(比较危险)
变量
[存储类型] 数据类型 标识符 = 值 TYPE NAME = VALUE
#include <stdlib.h>
#include <stdio.h>
void func() {
static int x = 1;
x++;
printf("%d\n", x);
}
int main() {
func();
func();
func();
}
2
3
4
- extern 说明型 意味着不能改变被说明的量的值或类型 可以用来扩展外部变量的作用域
#ifndef EXTERN_H__
#define EXTERN_H__
void func();
#endif
#include "extern.h"
extern int i; // 不定义 而是引用了其他地方的i
int func() {
printf("[%s]%d\n", __FUNCTION__, i);
}
#include "stdlib.h"
#include "stdio.h"
#include "extern.h"
int i = 10;
int main() {
printf("[%s]%d\n", __FUNCTION__, i);
}
表达式
逻辑运算符的短路性
#include <stdio.h>
#include <stdlib.h>
int main() {
int a = 1, b = 2, c = 3, d = 4;
int m = 1, n = 1;
(m = a > b) && (n = c > d);
printf("m = %d\n n = %d\n", m, n); // m : 0 n : 1
}
sizeof
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("%lu, %lu, %lu, %lu, %lu, %lu, %lu\n",
sizeof(int),sizeof(short), sizeof(long),
sizeof(double), sizeof(float), sizeof(char), sizeof(void*));
}
4, 2, 8, 8, 4, 1, 8
位运算
应用
将操作数中的第n位置1 其他位不变 num = num | 1 << n; 将操作数中的第n位置0 其他位不变 num = num & ~(1<<n); 测试第n位: if(num & (1<<n))
IO
变长参数
int main() {
int i = 123;
printf("%4d\n", i);
float f = 1.23455;
printf("%.3f\n", f);
char* s= "helloworld";
printf("%10.5s\n", s);
}
刷新缓冲区
int main() {
printf("[%s:%d] before while().", __FUNCTION__, __LINE__);
while(1);
printf("[%s:%d] after while().", __FUNCTION__, __LINE__);
}
正确写法
#include <stdlib.h>
#include <stdio.h>
int main() {
printf("[%s:%d] before while().]\n", __FUNCTION__, __LINE__);
// 或者
//printf("[%s:%d] before while().", __FUNCTION__, __LINE__);
//fflush(stdout);
while(1);
printf("[%s:%d] after while().", __FUNCTION__, __LINE__);
}
int main() {
int i;
scanf("%d", &i);
printf("%d\n", i);
}
scanf 在使用 %s 的时候要特别小心
#include <stdio.h>
#include <stdlib.h>
int main() {
char S[3];
scanf("%s", S); // 如果输入 abcdef
printf("%s", S); // 可能会出现段错误
}
scanf 在循环中使用的时候要特别小心
int main() {
int ret = 0;
int d = 0;
while(1) {
ret = scanf("%d, d);
if (ret == -1) {
perror("Error");
break;
}
printf("&d\n", d);
}
exit(0);
}
处理换行
int main() {
int i = 0;
char c = 0;
scanf("%d", &i);
scanf("%*c%c", &c);
// 或者
//getchar();
//scanf("%c", &c);
printf("i = %d, c = %c", i, c);
}
流程控制
跳过
数组
构造类型 连续存放
一维数组
[存储类型] 数据类型 标识符[下标]
初始化
static int a[10];
int a[3] = {1, 2, 3};
元素引用
数组名
一个常量
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr[3] = {1, 2, 3};
printf("%ld\n", sizeof(arr));
// 下面这句是错的
arr = {4, 5, 6};
for (int i = 0;i < sizeof(arr)/sizeof(int);i++) {
printf("%d", *(arr+i));
}
}
数组越界
c对数组不进行越界检查,需要格外小心
练习
#include <stdio.h>
#include <stdlib.h>
int main() {
int fib[10] = {1, 1};
for (int i = 2;i < 10;i++) {
fib[i] = fib[i-1]+ fib[i-2];
}
for (int i = 0;i < 10;i++) {
printf("%d ", fib[i]);
}
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr[] = {2, 3, 5, 4, 6, 7, 1, 9};
for (int i = 0;i < sizeof(arr)/sizeof(int);i++) {
for (int j = 0;j < sizeof(arr)/sizeof(int)-1-i;j++) {
if(arr[j] > arr[j+1]) {
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
for (int i = 0;i < sizeof(arr)/sizeof(int);i++) {
printf("%d ", arr[i]);
}
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr[] = {3, 2, 5, 4, 9, 7, 1, 6};
for (int i = 0;i < sizeof(arr)/sizeof(int);i++) {
int m = i;
for (int j = i+1;j < sizeof(arr)/sizeof(int);j++) {
if(arr[j] < arr[m]) {
m = j;
}
}
if (m != i) {
int tmp = arr[i];
arr[i] = arr[m];
arr[m] = tmp;
}
}
for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
printf("%d ", arr[i]);
}
}
二维数组
[存储类型] 数据类型 标识符[行下标][列下标]
int main() {
int a[M][N] = {1, 2, 3, 4, 5};
int b[][N] = {1, 2, 3, 4, 5};
int c[M][] = {1, 2, 3, 4, 5}; // 错误
for (int i = 0;i < M;i++) {
for (int j = 0;j < N;j++) {
printf("%d ", *(a+i+j*));
}
}
}
深入理解二维数组
a[2][3] = b[3] + c[3] a[0] = b[0] a[1] = c[0]
字符数组
定义以及初始化
[存储类型] char 标识符[]
注意部分初始化的时候,剩余部分会自动初始化为’\0’
IO
scanf 无法获取带有分隔符的字符串(\t , \n , )
常用函数
- strlen & sizeof
- strcpy & strncpy
- strcat & strncat
- strcmp & strncmp
单词统计
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRSIZE 1024
int main() {
char str[STRSIZE] = {};
fgets(str, STRSIZE, stdin);
int count= 0, flag = 0;
for (int i = 0;str[i] != '\0';i++){
if (str[i] == ' ') {
flag = 0;
} else if(!flag) {
count++;
flag = 1;
}
}
printf("%d\n", count);
}
指针
64位环境 指针类型占用8个字节 32位环境 指针类型占用4个字节
变量与地址
变量对某块内存的抽象表示 指针 == 地址 变量名 == 抽象出来的某块空间的别名
指针与指针变量
int i = 1;
int *p = &i;
int ** q = &p;
直接访问与间接访问
i = 1;
&i = 0x2000;
p = 0x2000;
&p = 0x3000;
*p = 1;
q = 0x3000;
&q = 0x4000;
*q = 0x2000;
**q = 1;
空指针与野指针
空类型
char *s = "hello";
void *i = s;
定义与初始化的写法
指针运算
& * 关系运算 ++ –
指针与数组
指针与一维数组
#include <stdlib.h>
#include <stdio.h>
int main () {
int a[3] = {1, 2, 3};
// a是常量 p是变量
int *p = a;
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
printf("%p -> %d\n", p+i, *(p+i));
}
}
p++ != p+1
#include <stdlib.h>
#include <stdio.h>
int main () {
int a[3];
int *p = a;
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
scanf("%d", p++);
}
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
printf("%d\n", *(p++));
}
}
指针与二维数组
#include <stdlib.h>
#include <stdio.h>
int main() {
int a[2][3] = {{1, 2, 3},{ 4, 5, 6}};
int (*p)[3] = a;
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
for (int j = 0;j < sizeof(*a)/sizeof(**a);j++) {
printf("%d ", *(*(p+i)+j));
}
}
}
#include <stdlib.h>
#include <stdio.h>
int main() {
int a[2][3] = {{1, 2, 3},{ 4, 5, 6}};
int *p = &a[0][0];
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
for (int j = 0;j < sizeof(*a)/sizeof(**a);j++) {
printf("%d ",*(p+(i * sizeof(*a)/sizeof(**a))+j));
}
}
}
const与指针
const float pi = 3.14; // 常量化变量
先看到指针就是指针 先看到常量就是常量
const int* p;
int const *p;
char *strcpy(char *restrict dest, const char *src); // src是源字符串 不应该被修改
- 指针常量 指向的位置不能变 可以通过这个指针修改内存的值
int *const p;
const int *const p;
指针数组与数组指针
指针数组
int *arr[3]
指针数组排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *name[5] = {"golang", "java", "c", "dart", "erlang"};
int k;
char *tmp;
for (int i = 0;i < (sizeof(name)/sizeof(*name))-1;i++) {
k = i;
for (int j = i+1;j < (sizeof(name)/sizeof(*name));j++) {
if (strcmp(name[k], name[j]) > 0) {
k = j;
}
}
if (k != i) {
tmp = name[i];
name[i] = name[k];
name[k] = tmp;
}
}
for (int i = 0;i < (sizeof(name)/sizeof(*name));i++) {
printf("%s\n", *(name+i));
}
}
数组指针
int a[2][3] = {{1, 2, 3},{ 4, 5, 6}};
int (*p)[3] = a;
#include <stdlib.h>
#include <stdio.h>
int main() {
int a[2][3] = {{1, 2, 3},{ 4, 5, 6}};
int (*p)[3] = a;
for (int i = 0;i < sizeof(a)/sizeof(*a);i++) {
for (int j = 0;j < sizeof(*a)/sizeof(**a);j++) {
printf("%d ", *(*(p+i)+j));
}
}
}
多级指针
没啥好说的
函数
函数的定义
#include <stdlib.h>
#include <stdio.h>
int main() {
exit(printf("Hello!\n"));
}
函数的传参
函数的调用
#include <stdlib.h>
#include <stdio.h>
int max(int a, int b, int c) {
int tmp = a > b ? a : b;
return tmp > c ? tmp : c;
}
int min(int a, int b, int c) {
int tmp = a < b ? a : b;
return tmp < c ? tmp : c;
}
int dist(int a, int b, int c) {
return max(a, b, c) - min(a, b, c);
}
int main() {
printf("%d\n", dist(8, 5, 10));
}
#include <stdio.h>
#include <stdlib.h>
int func(int n) {
if (n < 0) {
return -1;
}
if (n == 1 || n == 2) {
return 1;
}
return func(n-1) + func(n-2);
}
int main() {
int n;
scanf("%d", &n);
printf("fib %d = %d", n, func(n));
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
int func(int n) {
if (n < 0) {
return -1;
}
if (n == 0 || n == -1) {
return 1;
}
return n * func(n - 1);
}
int main() {
int n;
scanf("%d", &n);
printf("%d! = %d", n, func(n));
exit(0);
}
函数与数组
#include <stdlib.h>
#include <stdio.h>
// 注意这里的int *arr 的大小是8个字节 是一个普通的指针不是数组 所以一定要传大小
void printarr(int *arr, int size) {
for (int i = 0;i < size;i++) {
printf("%d ", *(arr+i));
}
printf("\n");
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
printarr(arr, sizeof(arr)/sizeof(*arr));
}
#include <stdlib.h>
#include <stdio.h>
void printarr(int *arr, int size) {
for (int i = 0;i < size;i++) {
printf("%d ", *(arr+i));
}
printf("\n");
}
void printarr2(int (*p)[3], int m , int n) {
for (int i = 0;i < m;i++) {
for (int j =0;j < n;j++) {
printf("%4d ", *(*(p+i)+j));
}
printf("\n");
}
}
int main() {
int arr[][3] = {1, 2, 3, 4, 5, 6};
printarr2(arr, 2, 3);
}
函数的指针
#include <stdio.h>
#include <stdlib.h>
#define M 2
#define N 3
int *findnum(int (*p)[N], int num) {
if (num > M - 1) {
return NULL;
}
return *(p + num);
}
int main() {
int arr[M][N] = {{1, 2, 3},{ 4, 5, 6}};
int *res = findnum(arr, 1);
for (int i = 0; i < N; i++) {
printf("%d ", *(res + i));
}
}
指向指针函数的函数指针数组
int *(*funcp[N])(int)
实际例子
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void *),
void *restrict arg);
构造类型
结构体
产生及意义
描述复杂的数据类型
类型描述
struct node_st{
type1 name1;
type2 name2;
...
};
嵌套定义
struct day {
int H;
int M;
int S;
};
struct student_st{
char *name;
day day;
};
定义变量 初始化以及成员引用
struct A {
int i;
char c;
float f;
};
int main() {
// TYPE NAME = VALUE;
struct A a = {123, 'A', 2.22}; // 初始化
struct A a_ = { .c = 'A', .f = 2.22}; // 部分初始化
struct A *ap = { .c = 'A', .f = 2.22}; // 部分初始化
printf("%d %c %.2f\n",a.i, a.c, a.f); // 成员引用
// 123 A 2.22
printf("%d %c %.2f\n",a_.i, a_.c, a_.f); // 成员引用
// 0 A 2.22
printf("%d %c %.2f\n",ap->i, ap->c, ap->f); // 成员引用
// 0 A 2.22
}
占用内存空间大小
addr % sizeof(type) 不能整除的话就要继续往下偏移
#include <stdio.h>
#include <stdlib.h>
struct A {
int i;
char c;
float f;
};
// 可以使用下面的方法取消对齐 常用于网络通信
struct B {
int i;
char c;
float f;
}__attribute__((packed));
int main() {
struct A a;
struct B b;
printf("A = %ld\n", sizeof(a));
printf("B = %ld\n", sizeof(b));
}
共用体
产生及意义
N选一 多个成员共用一块空间 取最大的成员的类型大小作为共用体的类型大小
类型描述
union test_un{
int i;
float f;
double d;
char ch;
};
嵌套定义
同结构体 可以互相嵌套
定义变量 初始化以及成员引用
成员引用:
32位的无符号数的高16位和低16位相加
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
int main() {
uint32_t i = 0x11223344;
printf("%x\n", (i>>16)+(i&0xFFFF));
}
另一种写法
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
union {
struct {
uint16_t i;
uint16_t j;
}x;
uint32_t y;
}u;
int main() {
uint32_t i = 0x11223344;
printf("%x\n", (i>>16)+(i&0xFFFF));
u.y = 0x11223344;
printf("%x\n", u.x.i + u.x.j);
}
枚举
enum 标识符{
成员1;
...
};
enum dar {
MON = 1,
TUS,
WEB,
THR,
FRI,
SAT,
SUN,
};
int main() {
enum day a = FRI;
printf("%d\n", a);
}
enum status {
RUNNING = 1,
STOP,
PAUSE,
};
struct job {
int id;
int state;
time_t start, end;
};
int main() {
struct job_st job1;
switch(jobs.state) {
case RUNNING:
// TODO
break;
case STOP:
// TODO
break;
case PAUSE:
// TODO
break;
default:
// TODO
abort();
}
}
typedef
typedef type typename
typedef int INT
int main() {
INT i = 9;
}
typedef 和 define 的区别
#define IP int *
type int *IP;
int main() {
// 宏
IP p, q;
int *p, q; // 一个int * 一个int
// typedef
IP p, q;
int *p, *q; // 两个int *
}
数组
typedef int ARR[6]; // int [6] 改名为 ARR
ARR a; // int a[6];
结构体
typedef struct {
int i;
float f;
}NODE, *NODEP;
函数
typedef int *FUNC(int)
函数指针
typedef int* (*FUNCP)(int)
动态内存管理
- malloc
- calloc
- realloc
- free
谁申请谁释放
#include <stdlib.h>
#include <stdio.h>
int main() {
int *ip = malloc(sizeof(int));
*ip = 1;
printf("%d\n", *ip);
free(ip);
}
动态数组
#include <stdlib.h>
#include <stdio.h>
int main() {
int *p;
int num = 5;
p = malloc(num * sizeof(int));
for (int i = 0;i < num;i++) {
scanf("%d", p+i);
}
for (int i = 0;i < num; i++) {
printf("%d ", *(p+i));
}
printf("\n");
exit(0);
}
内存申请与函数传值
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
void func1(void *p, size_t size) {
if(p == NULL) {
return;
}
p = malloc(size);
}
void func2(int **p, size_t size) {
if(*p == NULL) {
return;
}
*p = malloc(size);
}
void *func3(void *p, size_t size) {
if(p == NULL) {
return NULL;
}
p = malloc(size);
return p;
}
int main() {
int num = 100;
int *p = NULL;
func1(p, num); // 内存会泄露
func2(&p, num); // 传递二级指针
p = func3(p, num); // 将申请的内存返回
free(p);
exit(0);
}
free的理解
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
void func2(int **p, size_t size) {
if(*p == NULL) {
return;
}
*p = malloc(size);
}
int main() {
int num = 100;
int *p = NULL;
func2(&p, num); // 传递二级指针
free(p);
// p = NULL;
*p = 123;
printf("%d\n", *p); // 这个指针已经是野指针了
exit(0);
}
- free代表着变量p不再拥有原来指向内存空间的引用权限
- free后最好马上将指针置NULL
Makefile
工程管理 依赖管理
- makefile(用户自定义 更高优先级)
- Makefile(默认)
mytool:main.o tool1.o tool2.o
gcc main.o tool1.o tool2.o -o mytool
main.o:main.c
gcc main.c -c -Wall -g -o main.o
tool1.o:tool1.c
gcc tool1.c -c -Wall -g -o tool1.o
tool2.o:tool2.c
gcc tool2.c -c -Wall -g -o tool2.o
OBJS=main.o tool1.o tool2.o
CC=gcc
mytool:$(OBJS)
$(CC) $(OBJS) -o mytool
main.o:main.c
$(CC) main.c -c -Wall -g -o main.o
tool1.o:tool1.c
$(CC) tool1.c -c -Wall -g -o tool1.o
tool2.o:tool2.c
$(CC) tool2.c -c -Wall -g -o tool2.o
clean:
$(RM) $(OBJS) mytool -r
$^ 表示在上一句依赖关系中被依赖的所有文件 $@ 表示在上一句依赖关系中依赖项的目标文件
CFLAGS=-Wall -g -c
OBJS=main.o tool1.o tool2.o
CC=gcc
mytool:$(OBJS)
$(CC) $^ -o $@
main.o:main.c
$(CC) $^ $(CFLAGS) -o $@
tool1.o:tool1.c
$(CC) $^ $(CFLAGS) -o $@
tool2.o:tool2.c
$(CC) $^ $(CFLAGS) -o $@
clean:
$(RM) $(OBJS) mytool -r
% 表示同一个名字
CFLAGS=-Wall -g -c
OBJS=main.o tool1.o tool2.o
CC=gcc
mytool:$(OBJS)
$(CC) $^ -o $@
%.o:%.c
$(CC) $^ $(CFLAGS) -o $@
clean:
$(RM) $(OBJS) mytool -r
|