您的位置:首页 > 房产 > 建筑 > 互联网公司排名 中国_珠海专门做网站_培训网站有哪些_黄冈地区免费网站推广平台

互联网公司排名 中国_珠海专门做网站_培训网站有哪些_黄冈地区免费网站推广平台

2025/3/1 11:05:51 来源:https://blog.csdn.net/tianxhiliangtadi/article/details/145861261  浏览:    关键词:互联网公司排名 中国_珠海专门做网站_培训网站有哪些_黄冈地区免费网站推广平台
互联网公司排名 中国_珠海专门做网站_培训网站有哪些_黄冈地区免费网站推广平台

一、gcc编译器

1.1基本使用规范

gcc+[文件名]

回车

会自动生成文件名为a.out的可执行程序

1.2编译链接过程用到的选项

1.2.1指定生成名字的选项-o

gcc -o +[指定名字] +[文件名]

可以生产指定名字的可执行程序

1.2.2预处理选项-E

 如gcc -o test.i -E test.c

可进行预处理,完成宏替换等操作,并存到test.i中

1.2.3编译选项-S

  如gcc -o test.s -S test.i

可进行编译操作,将代码转换为汇编语言

1.2.4汇编选项-c

  如gcc -o test.o -c test.s

可进行汇编操作,将汇编语言转化为机器可识别代码

1.2.5链接

 完成了预处理,编译,汇编后的.o文件,可以直接进行链接形成可执行程序

只需gcc -o test.exe test.o

1.3标准库查看指令ldd

ldd指令可以进行库文件的查看

使用规范:

ldd+[文件名]

如:

1.3补:常用的标准库libc.so.6

此时的test可执行程序依托于libc.so.6标准库,同时Linux中的许多指令也同样依托于它

如:

二、动态/静态库与动态/静态链接

2.1动态/静态库是什么

动态库:以.so为后缀的库,称为动态库,在Windows中为.dll

静态库:以.a为后缀的库,称为静态库,在Windows中为.lib

2.1补:①先有语言还是先有编译器

先有编译器,最开始是用二进制代码写出来第一个编译器(汇编语言编译器),此后再通过编译器自举(即使用汇编语言在当前编译器下写其他语言编译器)来完成其他语言的编译器

②为什么编译过程要经历汇编这一阶段?而不是直接转化为机器可识别代码

将语言转化为机器可识别代码是一个巨大的工程,其中有着无数的问题,而转为汇编语言就要简单得多

并且汇编语言转化机器可识别代码的工作完成进度很高,为了方便所以选择经历转化汇编这一阶段

2.2动态/静态链接是什么

2.2.1动态链接

编译器提前加载动态库中所需代码的地址,程序运行过程中走到对应的一步会跳转到动态库中

2.2.2静态链接

把我们要访问的方法从静态库中拷贝到自己的可执行程序当中

2.2.3各自的优缺点

①动态库

优点:节省资源,可执行程序大小较小

缺点:一旦动态库缺失,程序会无法运行;要进行函数跳转,可执行程序耗时比较长

②静态库

优点:不依赖其他库,即使库丢失依旧可以运行

缺点:比较浪费资源,可执行程序大小较大

2.2.3补:库和链接有什么关系

要想进行对应的链接,必须要有对应的库

2.3连接方式的查看与选择

2.3.1查看连接方式的指令file

使用规范为

file+[可执行程序名]

如:

从中可以看出连接方式:

动态链接为dynamically linked

静态链接为statically linked

2.3.2链接方式的选择

默认生成采用动态链接

若要更改为静态链接,需要使用-static选项

如:

gcc -o sta_test test.c -static


2.3.2补:云服务器默认没有安装C/C++的静态标准库

c:yum install -y glibc-static

c++:yum install -y libstdc++-static

三、自动化构建工具make/makefile

3.1自动化构建工具的意义

我们在Linux中进行编译链接形成可执行程序可每次都需要写一行gcc指令,有没有更简单的方法呢?

有的,利用make和makefile进行配合即可简化这一步

3.2make/makefile是什么?应该怎么使用?

make是一个指令

makefile是一个文件

使用样例:

假如在当前目录中有一个文件test.c

我们只需要创建一个文件makefile

在其中写入

test:test.c

        gcc -o test test.c

然后执行指令

make

即可自动形成test可执行程序

3.3makefile的本质与组成

⭐3.3.1通过例子拆分组成结构

结合例子

makefile的本质就是依赖关系和依赖方法的集合

二者需要紧跟着写,且依赖方法要以tab开头 

3.3.2自动清理的配置

在使用如VS2022等编译器的时候,我们编译运行时自动生成可执行文件后会自动清理,那么在Linux中可不可以实现呢?

可以的,makefile可以帮助我们完成

方法是:

在makefile文件后添加

.PHONY:clean

clean:

        rm -f test

在外面运行指令

make clean

即可实现自动删除可执行文件 

其构成解析为:

 ②

make clean的原理是:

形成clean目标文件的时候会自动执行其依赖方法

3.3.3依赖方法可以是任意指令,且默认回显

执行依赖方法时,任意指令都可以支持,且默认将代码回显

可以选择跳过回显:每行前面加一个@

例如:

test:test.c

        @echo "开始编译"

        @gcc -o test test.c

        @echo "编译完成"

 可以实现make的时候显示“开始编译”

若代码编译一切顺利会形成test可执行程序并显示“编译完成”

3.3.4.PHONY的功能是什么

可以让目标文件对应的方法总是被执行

例如gcc执行前的比较过程就会被忽略(参考3.4.2)

例1:在makefile中

.PHONY:test

test:test.c

        gcc -o test test.c

这样以后在形成test可执行程序的时候不会再关注时间的比较,而绝对执行gcc更新可执行程序

例2:在3.3.2的例子中

我们删除.PHONY:clean并不影响功能

但这仅仅是因为rm本就不关心时间,不会被限制执行,可是往往clean中并不只是rm一行,在那个时候就需要声明伪目标了

3.4make的使用过程

3.4.1stat指令查看文件属性来读取时间的原理

stat+[文件名]

可以查看当前文件的详细属性

其中有三个时间

Access:最近访问时间(参考价值较低)

Change:最近文件属性被改变时间

Modify:最近文件内容被改变时间

3.4.2在使用make时,gcc编译过程连续运行的话有时候会提示不让编译,为什么?

在运行gcc编译指令之前,会对比源文件和可执行程序的Modify时间,若可执行程序的Modify时间更晚,则不会进行编译

⭐3.5makefile/make的基本原理

①makefile文件会被make指令从上到下扫描,如果单独执行make指令,会执行第一对依赖关系和依赖方法;若要执行其他组,需要make+[目标名]

②makefile执行gcc的过程中,如果发生了语法错误,会终止推导过程

③make解释makefile时时自动推导的,会一直根据目标文件推到到需要目标文件的一步,再逆向执行依赖方法

④make默认只会执行一个可执行程序

3.6make和makefile的其他自动功能

3.6.1自动由目标文件向依赖文件推导

其实我们要由test.c生成test可执行程序是需要多步的,完整起来写应为

test:test.o

        gcc -o test test.o

test.o:test.s

        gcc -c test.s -o test.o 

test.s:test.i

        gcc -S test.i -o test.s 

test.i:test.c

        gcc -E test.c -o test.i

 .PHONY:clean

clean:

        rm -f test test.o test.s test.i

 根据3.5中基本原理③,之所以可以直接写test:test.c是因为make的自动推导

3.6.2makefile中也可以直接定义变量,其中变量名有独特的使用方法

其方法是:

[变量名]=[文件名]

例如对于3.6.1中代码(我们仅体现两步test->test.o  test.o->test.c)

原代码:

test:test.o

        gcc -o test test.o

test.o:test.c

        gcc -c test.c -o test.o 

 .PHONY:clean

clean:

        rm -f test test.o

使用类型定义后:

bin=test

src=test.o

$(bin):$(src)

        gcc $^ -o $@

%.o:%.c

        gcc -c %<

 .PHONY:clean

clean:

        rm -f $(bin) test.o

我们对其中细节进行一下解释:

3.6.3一次性形成两个可执行程序的方法

原理是通过声明一个伪目标,使其依赖文件同时包含两个可执行程序

但不包含任何依赖方法

 如:

bin1=test1

src1=test1.c

bin2=test2

src2=test2.c

.PHONY:all

all:$(bin1) $(bin2)

$(bin1):$(src1)

        gcc $^ -o $@

$(bin2):$(src2)

        gcc $^ -o $@

 .PHONY:clean

clean:

        rm -f $(bin1) $(bin2)

四、综合样例

4.1知识补充:回车和换行是一个概念吗?

不是一个概念,回车指光标回到一行起始,而换行指光标直接移到下一行

键盘中的回车其实本质上是:先回车再换行,C语言中的\n也是做了特殊处理,完成回车加换行

4.2知识补充:缓冲区的问题

假如有这样一组程序

printf("hello world");

sleep(2);

printf("hello world\n");

sleep(2);

运行起来的结果是

①两秒后出现hello world同时程序结束

②直接出现hello world,两秒后程序结束

我们可以确定printf一定会早于sleep执行,可为什么会出现这一差异呢?

实际上,\n进行了一次强制缓冲区刷新

缓冲区图示:

 

4.2补:

①sleep函数:程序暂停

在Linux中,头文件#include<unistd.h>下有

1>sleep函数

2>usleep函数

他们的传入值是int,作用是让程序暂停一段时间,其单位对应是:

sleep:秒

usleep:微秒(1000000微秒=1秒)

②指定刷新缓冲区

可以利用#include<stdio.h>下的

int fflush(FILE* stream)

函数,来制定刷新缓冲区

需要传入一个stdout流

4.3简单的计时器程序

根据上述知识储备,可以完成一个简单的计时器程序

需要注意几个细节:

①打印时用\r来覆盖,用fflush来刷新缓冲区

②用sleep做出间隔

③printf(“-2d\r”,...)来保证打印的数字始终靠左,且二位数也不受影响

④循环完成利用\n完成一次换行

源码:

makefile:

bin = test
src = test.ctest:test.cgcc $^ -o $@
.PHONY:clean
clean:rm -f test

test.c

#include <stdio.h>
#include <unistd.h>int main()
{int num=10;while(num >= 0){printf("%-2d\r",num);num--;fflush(stdout);sleep(1);}printf("\n");return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com