C编程

  • 从Hello World开始
    • 编写代码
    • 编译代码
    • 编译流程
  • Makefile的使用
    • Makefile 规则格式
    • Makefile 变量
    • Makefile 伪目标
    • Makefile 条件判断
    • Makefile 函数使用

从Hello World开始

vim编辑器前边已经介绍过,这里学习一下gcc编译器

gcc [选项] [文件名字]-c: 只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o: <输出文件名>用来指定编译结束以后的输出文件名,如果使用这个选项的话 GCC 默认编译出来的可执行文件名字为 a.out。
-g: 添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编译的时候生成调试所需的符号信息。
-O: 对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进行优化,这样产生的可执行文件执行效率就高。
-O2: 比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。

编写代码

使用vim编辑器编写(.c)源代码,在那之前先进行一下vim设置,修改/etc/vim/vimrc文件,文件末尾添加命令,方便C编程。

sudo vi /etc/vim/vimrc添加内容:
set ts=4   //设置tab制表符为4
set nu      //设置行标号//set noexpandtab

编辑main.c文件,输出hello world!。

编译代码

使用GCC 编译器编译源代码(.c)并链接生为可执行文件(.out)
不同的架构需要不同的gcc编译器,x86架构和arm架构就不同。

gcc main.c -o main   //编译+链接生成可执行文件
./main              //运行程序gcc -c main.c     //编译
gcc main.o -o main  //链接
./main              //运行程序

编译流程

GCC 编译器的编译流程是:预处理、编译、汇编和链接。

//源代码(.c)生成目标代码(.o)
预处理就是展开所有的头文件、替换程序中的宏、解析条件编译并添加到文件中。
编译是将经过预编译处理的代码编译成汇编代码,也就是我们常说的程序编译。
汇编就是将汇编语言文件编译成二进制目标文件。

//目标代码(.o)和库代码、启动代码链接成可执行文件(.out)
链接就是将汇编出来的多个二进制目标文件链接在一起,形成最终的可执行文件,链接的时候还会涉及到静态库和动态库等问题。

Makefile的使用

Makefile是一个文件,就是控制gcc编译器**去编译、链接数量较多的源文件。**大大节约了开发时间。

1.首先在工程目录下创建Makefile文件。
2.Makefile文件中格式

目标文件: 依赖文件集合命令 1命令 2……//命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
//命令即为shell命令

3.使用make命令,make 命令会在当前目录下查找以Makefile(makefile 其实也可以)命名的文件。
4.当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标。

Makefile 规则格式

除了 Makefile 的“终极目标”所在的规则以外,其它规则的顺序在 Makefile 中是没有意义的,“终极目标”就是指在使用 make 命令的时候没有指定具体的目标时, make 默认的那个目标,它是 Makefile 文件中第一个规则的目标,如果 Makefile 中的第一个规则有多个目标,那么这些目标中的第一个目标就是 make 的“终极目标”。

和python一样 # 为注释

例如:

#Makefile文件内容main为终极目标
1 main: main.o input.o calcu.o
2   gcc -o main main.o input.o calcu.o
3 main.o: main.c
4   gcc -c main.c
5 input.o: input.c
6   gcc -c input.c
7 calcu.o: calcu.c
8   gcc -c calcu.c
9
10 clean:
11  rm *.o
12  rm main
#命令操作
make        #生成可执行文件
make clean  #清除指定文件

Makefile 变量

问题:如果需要重复的输入文件名会很浪费时间也不容易修改。
解决:Makefile 也支持字符串变量

1、赋值符“=”

1 name = zzk            #zzk赋值给变量name
2 curname = $(name)        #$(name)取值
3 name = zuozhongkai   #修改变量内容
4
5 print:
6   @echo curname: $(curname)#打印字符make print
zuozhongkai

“#”作为注释标志,“$”(变量)取字符,
print: @echo 字符串 打印内容,@表示make命令不会打印。

2、赋值符“:=”

1 name = zzk            #zzk赋值给变量name
2 curname := $(name)       #$(name)取值
3 name = zuozhongkai   #修改变量内容
4
5 print:
6   @echo curname: $(curname)#打印字符make print
zzk

“:=”和“=”的区别就是,“:=”给变量赋值后,该变量得到的字符串就确定了。

curname ?= zuozhongkai

如果变量 curname 前面没有被赋值,那么此变量是“zuozhongkai”
curname:“我没有值,我要你的”

如果前面已经赋过值了,那么就使用前面赋的值。
curname:“我已经有值了,不需要了”

4、变量追加“+=”

objects = main.o inpiut.o
objects += calcu.oobjects 变成了“main.o input.o calcu.o”

5、sinclude 和 include
在 Makefile 中都是读取指定文件内容,这里读取文件 ( s r c t r e e ) / a r c h / (srctree)/arch/ (srctree)/arch/(ARCH)/config.mk 的内容。 sinclude 读取的文件如果不存在的话不会报错。

6、变量使用规则

$(CONFIG_SYS_ARCH:"%"=%) // 也就是提取CONFIG_SYS_ARCH 里面双引号“”之间的内容。比如 :CONFIG_SYS_ARCH=“arm”的话,ARCH=arm。## Makefile 自动化变量
**自动化变量**就是这种变量会把模式中**所定义的一系列的文件**自动的挨个取出,直至**所有的符合模式的文件**都取完。
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020072611371227.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxNzUzMDUy,size_16,color_FFFFFF,t_70)```bash
1 objects = main.o input.o calcu.o
2 main: $(objects)
3   gcc -o main $(objects)
4
5 %.o : %.c     #目标文件.o 依赖文件.c
6   gcc -c $<    #所有.c编译成.o
7
8 clean:
9   rm *.o
10  rm main

“%”makefile命令类似于通配符,“$<”自动化变量,所有一系列变量。

Makefile 伪目标

伪目标不代表真正的目标名,通过指定这个伪目标来执行其所在规则的定义的命令

#如果目录中有clean文件,则会被认为是目标名
clean:rm *.orm main
#这样不怕目录中有clean,明确是伪命令
.PHONY : cleanrm *.orm main

Makefile 条件判断

<条件关键字><条件为真时执行的语句>
else<条件为假时执行的语句>
endif

条件关键字有 4 个: ifeq、 ifneq、 ifdef 和 ifndef
ifeq 用来判断是否相等, ifneq 就是判断是否不相等

ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’ ,‘<参数 2>’
ifeq “<参数 1>” , “<参数 2>”
#参数即字符

ifdef 用来判断是否相等, ifndef 就是判断是否不相等

ifdef <变量名>
ifndef <变量名>

Makefile 函数使用

Makefile 中的函数是已经定义好的,我们直接使用。

$(函数名 参数集合)
#或者
${函数名 参数集合}
#参数集合之间用“,”隔开

1、函数 subst,用来完成字符串替换

#函数返回被替换以后的字符串
$(subst <from>,<to>,<text>)   //将字符串<text>中的<from>内容替换为<to>#比如:
$(subst zzk,ZZK,my name is zzk) //把字符串“my name is zzk”中的“zzk”替换为“ZZK”

2、函数 patsubst,用来完成模式字符串替换

#函数返回被替换以后的字符串
$(patsubst <pattern>,<replacement>,<text>)    //查找字符串<text>中的单词是否符合模式<pattern>,如果匹配就用<replacement>来替换掉#比如:
$(patsubst %.c,%.o,a.c b.c c.c) //将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”

3、函数 dir,用来提取目录部分

#返回值是文件名序列<names>的目录部分
$(dir <names…>)   //从文件名序列<names>中提取出目录部分#比如:
$(dir </src/a.c>) //提取文件“/src/a.c”的目录部分,也就是“/src”。

4、函数 notdir,去除文件中的目录部分,也就是提取文件名

$(notdir <names…>)#比如:
$(notdir </src/a.c>)  //提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。

5、函数 foreach,用来完成循环

$(foreach <var>, <list>,<text>)    //把参数<list>中的单词逐一取出来放到参数<var>中,然后再执行<text>所包含的表达式

每次< text >都会返回一个字符串,循环的过程中, < tex t>中所包含的每个字符串会以空格隔开,最后当整个循环结束时,
< text >所返回的每个字符串所组成的整个字符串将会是函数 foreach 函数的返回值。
6、函数 wildcard
问题:%只能用在规则中,不能用于函数。
解决:这就需要wildcard函数。

$(wildcard PATTERN…)#比如:
$(wildcard *.c) //获取当前目录下所有的.c 文件,类似“%”。

linux的学习就先到这,个人觉得主要还是实践练习,在后期学习的时候再做补充。

7、函数origin,返回值就是变量来源

$(origin <variable>)    #variable 是变量名比如:
$(origin V) //如果变量 V 是在命令行定义的那么它的来源就是"command line",返回command line。

8、filter 函数,过滤函数

$(filter <pattern...>,<text>)  //以 pattern 模式过滤 text 字符串中的单词,仅保留符合模式 pattern 的单词,
可以有多个模式。函数返回值就是符合 pattern 的字符串。比如:
$(filter 4.%,$(MAKE_VERSION)) //保留MAKE_VERSION中的4.%的字符

9、函数 firstword,获取首单词

$(firstword <text>)    //取出 text 字符串中的第一个单词,函数的返回值就是获取到的单词。

10、函数shell,执行shell命令

$(shell <command>) //执行命令行的shell脚本

linux C 编程入门相关推荐

  1. Linux动态链接库编程入门

    Linux动态链接库编程入门 转:http://blog.csdn.net/yang_rong_yong/article/details/3090212 动态链接库是一种通用的软件组件技术,是多种操作 ...

  2. 【学习笔记】Linux 系统编程入门

    Linux 系统编程入门 静态库与动态库 静态库命名规则 静态库的制作 静态库使用 动态库制作 动态库使用 加载动态库 静态库的优缺点 动态库的优缺点 Makefile 文件命名 工作原理 变量 模式 ...

  3. Linux网络编程 入门

    Linux网络编程入门 (转载) (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端          网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...

  4. 一文带你Linux系统编程入门

    文件和文件系统 文件是linux系统中最重要的抽象,大多数情况下你可以把linux系统中的任何东西都理解为文件,很多的交互操作其实都是通过文件的读写来实现的. 文件描述符 在linux内核中,文件是用 ...

  5. 【Linux】Linux系统编程(入门与系统编程)(一)(环境搭建、常见指令以及权限理解)

    目录 linux系统编程 : 1.推动技术进步的基本模式 2.理解操作系统的发展 Linux 背景介绍 UNIX发展的历史: Linux发展历史 开源 Linux的发行版本: a.技术角度 b.商业化 ...

  6. Linux 高并发服务器实战 - 1 Linux系统编程入门

    Linux 高并发服务器实战-1Linux系统编程入门 在本机和服务器端设置公共密钥(配置免密登录) 在本机cmd里输入 ssh-keygen -t rsa,生成本机的公密钥 在服务器端里也配置 ss ...

  7. 由尚德linux内核编程进阶教材,由尚德老师Linux内核编程入门视频教程

    由尚德老师讲解的Linux内核编程教程入门课程,此课程学完后可以接着学进阶篇,下载地址:http://blog.csdn.net/congxue/archive/2009/05/17/4194112. ...

  8. Linux 进程编程入门

    关于进程和线程的关系,之前一口君写过这几篇文章,大家可以参考下. 本文从头带着大家一起学习Linux进程 <搞懂进程组.会话.控制终端关系,才能明白守护进程干嘛的?> <[粉丝问答6 ...

  9. Linux网络编程入门

    (一)Linux网络编程--网络知识介绍 linux网络编程--网络知识介绍 客户端和服务端          网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. ...

  10. Linux网络编程入门 (转载)

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客 ...

最新文章

  1. 分类家族:二分类、多分类、多标签分类、多输出分类
  2. java jdk下载过慢 解决方案
  3. linux的命令行操作和shell的区别
  4. python实现简单的api接口-用python写一个restful API
  5. Swift数据类型(一)
  6. 特征层次分析、视觉特征语义探索(微调+预训练)
  7. TypeScript 2.5 发布,增加语言级重构
  8. Kafka是如何处理Netflix每天2万亿条消息的?
  9. MySQL Innodb数据库性能实践——VARCHAR vs CHAR
  10. python threading编程中的LOCK和RLOCK(可重入锁)
  11. 如你以安全模式启动计算机,如何以安全模式启动计算机?
  12. html表格内部虚线代码,各种表格样式示例及代码
  13. 一个不错微服务架构图
  14. python实现将点云的.bin格式文件转化为.txt格式
  15. 从单目视觉信息学习深度信息(一)
  16. 数值分析:高斯消元法
  17. python的mapl画图y轴排_python中用Matplotlib做多个纵轴 (多y轴)
  18. java SWT:MouseEvent,KeyEvent中stateMask字段的用法
  19. Java中为什么不能用“==”判断字符串是否相等
  20. WKT Geometry

热门文章

  1. 一定要注意网站图片版权问题!
  2. 关于访问后端接口报404的问题——全网最详细的404错误详解
  3. 通过PS把月亮“搬”到自己的床上
  4. 生成与获取token
  5. 管理小故事精髓 100例(转) 1
  6. EF Power Tools参数不正确的解决方法
  7. Win10系统QQ无法登陆,代码00001
  8. 营销自动化的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  9. StarUML 3.0破解
  10. 管管我吧,我很听你的话