shell数组 Linux分文件 make工具
shell中的数组
shell 支持稀疏数组
格式:数组名=(初始值1 初始值2,……)
数组名=([下标]=初始值 [下标]=初始值……)下标可以不连续
arr=([10]=10 [0]=0)
访问数组中的元素
${数组名[下标]} --> 获取数组中指定下标元素的值
获取数组中的所有元素
${数组名[*]} ---> 获取数组中所有元素
${数组名[@]} ---> 获取数组中所有元素
获取数组中元素的个数
${#数组名[*]} ---> 获取数组中元素个数
${#数组名[@]} ---> 获取数组中元素个数
${#arr[下标]} ---> 获取数组中指定下标元素的长度(字符长度)
数组切片
取数组中某一段元素的值
格式:
${数组名[*]:起始位置(起始下标):长度}
${数组名[@]:起始位置(起始下标):长度}
分文件
整个工程包含:
多个.c和多个 .h 文件
main.c ---> main() //有main函数,其余文件均由main.c调用
xxx.c ----> 多个.c文件,封装函数实现多个功能(不同功能函数接口)
.h 头文件
包含:
- 包含其他的头文件
- 函数的声明
- 构造数据类型
- 宏定义
- 重定义的名字
- 全局变量
include 引用时 " " 和 <> 的区别
#include <stdio.h>
系统定义的头文件:去系统目录下查找头文件
#include "add.h"
自定义头文件:先从当前目录下查找,如果没有再去系统目录下查找头文件
条件编译
编译器根据条件的真假决定是否编译相关代码
根据宏是否定义
语法格式:
#ifdef <macro>
...
#else
...
#endif
#include "function.h"
#define DEF
int main(int argc, char const *argv[])
{
#ifdef DEF
printf("YES\n");
#else
printf("NO\n");
#endif
return 0;
}
根据宏的值是否为真
#if <macro>
...
#esle
...
#endif
#include <stdio.h>
#include "function.h"
#define DEF 0
int main(int argc, char const *argv[])
{
#if DEF
printf("YES\n");
#else
printf("NO\n");
#endif
return 0;
}
根据宏是否定义,作用:防止头文件重复包含(加上包不错)
#ifndef <macro> 注意:两个宏名要相同
#define <macro>
....
#endif
gcc编译步骤
预处理: 处理以#开头的内容,展开头文件、替换宏定义、删除注释,但是不会进行语法检查
gcc -E xxx.c -o xxx.i
编译:检查语法错误,有错报错,没错将 .i 文件转换成 .s 汇编文件
gcc -S xxx.i -o xxx.s
汇编:将汇编文件转化成二进制文件(不可执行)
gcc -c xxx.s -o xxx.o
链接:链接库文件,将不可执行的二进制文件转化成可执行的二进制文件
gcc xxx.o -o xx
gcc xx.c 默认生成 a.out
gcc xxx.c -o xxx
make工具
- 工程管理器,管理较多文件
Make 工程管理器也就是个"自动编译管理器",这里的"自动"
是指它能够根据文件时间戳,发现更新过的文件而减少编译工作量同时它通过读入
Makefile 文件的内容来执行大量的编译工作
- make工具的作用
当项目中包含了多个.c文件,但只对其中一个文件进行了修改,那用 gcc 编译会将所有的文件从头到尾编译一遍,这样的效率非常低
所以通过 make 工具,可以查找到修改过的文件(根据时间戳),只对修改过的文件进行编议,这样大大的减小的编译时间,提高编译效率
- Makefile是make读入的唯一配置文件
Makefile工程文本文件
- Makefile的编写格式:
目标: 依赖
<tab>命令
Makefile 根据以下步骤书写:
gcc xxx.o -o xxx
gcc -c xxx.c -o xxx.o
例:一个Makefile文件
main: main.o function.o
gcc main.o function.o -o main
main.o: main.c
gcc -c main.c -o main.o
function.o: function.c
gcc -c function.c -o function.o
目标: 伪命令
伪命令它的目的不是创建目标文件,而是执行下面的命令
# 第一个版本
all: main # 一般makefile中的第一个目标都是 all:可执行文件
#为了保证,最后makefile文件执行后一定会生成一个可执行文件
main: main.o function.o
gcc main.o function.o -o main
main.o: main.c
gcc -c main.c -o main.o
function.o: function.c
gcc -c function.c -o function.o
.PHONY: clean
clean:
rm -rf *.o main
执行:make clean
规则中 rm 命令不是为了创建 clean 这个文件而是执行删除命令。当工作目录中不存在clean 命名文件时,执行 make clean 命令 rm -rf *.o main总会被执行。
如果避免同名文件加 .PHONY:伪命令
Makefile变量
自己定义的变量:一般用大写表示变量名,取变量值用 $(变量名)
赋值方式: = := += ?=
- = ---->递归赋值(以最后一次赋值为准)
- := ---->立即赋值 (当前是什么值就立即是什么值)
- += ---->追加赋值(追加新的值)
- ?= ---->条件赋值(判断之前是否定义,如果定义不重新赋值,如果没有定义,则重新赋值)
预定义变量
系统预先定义好的一些变量,可能有默认值可能没有
RM 文件删除程序的名称,默认值为 rm -f
CC C编译器的名称,默认值是cc
CPP C预编译器的名称,默认值是$(CC)-E
CFLAGS C编译器的选项,无默认值
OBJS 生成的二进制文件或者目标文件,自己定义的
# 第二个版本
EXE=main
OBJS=main.o function.o
CC=gcc
CFLAGS=-c -g -Wall # -g:调试 -Wall: 显示警告
all: $(EXE)
$(EXE): $(OBJS)
$(CC) $(OBJS) -o $(EXE)
main.o: main.c
$(CC) $(CFLAGS) main.c -o main.o
function.o: function.c
$(CC) $(CFLAGS) function.c -o function.o
.PHONY: clean
clean:
$(RM) $(OBJS) $(EXE)
引入自动变量和通配符
$< 第一个依赖文件
$@ 目标文件的完整名称
$^ 所有不重复的依赖文件,以空格分开(自动)
通配符
%:是一种(字符串的)模式匹配,在Makefile的作用是有一个.o就匹配一个同名的.c
%.o:%.c
EXE=main
OBJS=main.o function.o
CC=gcc
CFLAGS=-c -g -Wall # -g:调试 -Wall: 显示警告
all: $(EXE)
$(EXE): $(OBJS)
$(CC) $^ -o $@
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
.PHONY: clean
clean:
$(RM) $(OBJS) $(EXE)
引入函数
make中提供了内置函数
因为内置函数是帮助程序员查找文件信息的,所以要求在查找路径下,只要程序需要的.c文件,没有其他程序的.c文件
wildcard
功能:根据给的条件,获取指定文件名(找文件名的功能)
$(wildcard 指定字符串的格式)
$(wildcard *.c) ---->找到当前路径下所有的.c文件的文件名
patsubst
功能:模式匹配,替换字符串
$(patsubst 源格式.c,目标格式,要替换的字符串)
$(patsubst %.c,%.o,main.c fun.c) ---> 获取到 main.c fun.c字符串,根据模式匹配,得到 main.o fun.o 字符串每一个参数之间以逗号作为分隔,要替换的字符串之间以空格作为分隔
#第四个版本
EXE=main
FILES=$(wildcard *.c)
OBJS=$(patsubst %.c,%.o,$(FILES))
CC=gcc
CFLAGS=-c -g -Wall
all: $(EXE)
$(EXE): $(OBJS)
$(CC) $^ -o $@
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
.PHONY: clean
clean:
$(RM) $(OBJS) $(EXE)