gcc-makefile-缓存区

本文详细介绍了C语言程序从源代码到可执行文件的翻译过程,包括预处理、编译、汇编和链接四个阶段,并展示了在Linux环境下使用gcc命令分别进行-E、-S、-c操作。文章还讨论了动态链接和静态链接的区别,以及make和makefile在构建项目中的作用。此外,提到了缓冲区对输出的影响和回车、换行的区别。
摘要由CSDN通过智能技术生成

程序翻译的过程

文本的C -> 计算机二进制

  1. 预处理(去注释,宏替换,头文件展开,条件编译...)
  2. 编译(c ->汇编)
  3. 汇编(汇编 ->可重定向二进制目标文件)
  4. 链接(链接多个 .o ,.obj ->合并形成一个可执行) .exe

sudo yum install -y gcc-c++

编译cpp的后缀可以是 cpp cc cxx

[hang@VM-4-14-centos 2]$ vim test.c [hang@VM-4-14-centos 2]$ gcc -E test.c -o mytest.i [hang@VM-4-14-centos 2]$ ls -al total 36 drwxrwxr-x 3 hang hang 4096 Aug 13 15:46 . drwxrwxr-x 3 hang hang 4096 Aug 13 15:44 .. drwxrwxr-x 3 hang hang 4096 Aug 11 18:34 3 -rw-rw-r-- 1 hang hang 16871 Aug 13 15:46 mytest.i -rw-rw-r-- 1 hang hang 72 Aug 13 15:45 test.c [hang@VM-4-14-centos 2]$ gcc -S test.c -o mytest.s [hang@VM-4-14-centos 2]$ ls -al total 40 drwxrwxr-x 3 hang hang 4096 Aug 13 15:46 . drwxrwxr-x 3 hang hang 4096 Aug 13 15:44 .. drwxrwxr-x 3 hang hang 4096 Aug 11 18:34 3 -rw-rw-r-- 1 hang hang 16871 Aug 13 15:46 mytest.i -rw-rw-r-- 1 hang hang 446 Aug 13 15:46 mytest.s -rw-rw-r-- 1 hang hang 72 Aug 13 15:45 test.c [hang@VM-4-14-centos 2]$ gcc -c test.c -o mytest.o [hang@VM-4-14-centos 2]$ ls -al total 44 drwxrwxr-x 3 hang hang 4096 Aug 13 15:47 . drwxrwxr-x 3 hang hang 4096 Aug 13 15:44 .. drwxrwxr-x 3 hang hang 4096 Aug 11 18:34 3 -rw-rw-r-- 1 hang hang 16871 Aug 13 15:46 mytest.i -rw-rw-r-- 1 hang hang 1496 Aug 13 15:47 mytest.o -rw-rw-r-- 1 hang hang 446 Aug 13 15:46 mytest.s -rw-rw-r-- 1 hang hang 72 Aug 13 15:45 test.c [hang@VM-4-14-centos 2]$ gcc mytest.o -o mytest [hang@VM-4-14-centos 2]$ ./mytest hello hang

-E 从现在开始进行程序的翻译,如果预处理完成就停下来!

-S 从现在开始进行程序的翻译,如果编译完成就停下来!

-c 从现在开始进行程序的翻译,如果汇编完成就停下来!

最后还进行了链接哦!

总称 ESc

相对应的文件名

. i 预处理后文件

. s 汇编文件

. o 可重定向目标文件


由上面我们可知,我们的C语言程序是离不开c库文件的

Linux :.so (动态库) .a (静态库)

windows : .dll(动态库) .lib (静态库)

[hang@VM-4-14-centos 2]$ ls /lib64/libc-2.17.so -al -rwxr-xr-x 1 root root 2156272 Sep 30 2020 /lib64/libc-2.17.so [hang@VM-4-14-centos 2]$ ls /usr/include/stdio.h /usr/include/stdio.h

前者提供C语言的方法实现,而后者提供C语言的方法列表和方法声明。两者结合我的源文件从而形成可执行的 .exe

一般链接的过程分为两种 1.动态链接 -----需要动态库

2. 静态链接 -----需要静态库

动态链接 将库中我所需要的方法(函数)的地址,填入到我的可执行程序中去,建立关联!(节省资源)

静态链接 将库中的方法(函数)实现拷贝到我们的可执行程序中去!! (占用资源)

gcc/ g++ 默认都是动态链接的

动态

[hang@VM-4-14-centos 2]$ gcc test.c -o mytest [hang@VM-4-14-centos 2]$ ldd mytest linux-vdso.so.1 => (0x00007ffcfc3d6000) libc.so.6 => /lib64/libc.so.6 (0x00007ff082193000) /lib64/ld-linux-x86-64.so.2 (0x00007ff082561000) [hang@VM-4-14-centos 2]$ file mytest mytest: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=fba7d19e45a3f2dd20790fe91fecb116394b7e8b, not stripped [hang@VM-4-14-centos 2]$ ls -al total 28 drwxrwxr-x 3 hang hang 4096 Aug 13 16:42 . drwxrwxr-x 3 hang hang 4096 Aug 13 15:44 .. drwxrwxr-x 3 hang hang 4096 Aug 11 18:34 3 -rwxrwxr-x 1 hang hang 8400 Aug 13 16:42 mytest -rw-rw-r-- 1 hang hang 72 Aug 13 15:45 test.c [hang@VM-4-14-centos 2]$ rm mytest

静态 (sudo yum install -y glibc-static /sudo yum install -y libstdc++-static )

[hang@VM-4-14-centos 2]$ gcc test.c -o mytest -static [hang@VM-4-14-centos 2]$ ldd mytest not a dynamic executable [hang@VM-4-14-centos 2]$ file mytest mytest: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=20456781d3a8ec1651d43345215bfe5ce26c2c6e, not stripped [hang@VM-4-14-centos 2]$ ls -al total 860 drwxrwxr-x 3 hang hang 4096 Aug 13 17:27 . drwxrwxr-x 3 hang hang 4096 Aug 13 15:44 .. drwxrwxr-x 3 hang hang 4096 Aug 11 18:34 3 -rwxrwxr-x 1 hang hang 861288 Aug 13 17:27 mytest -rw-rw-r-- 1 hang hang 72 Aug 13 15:45 test.c

注意观察 文件的类型及其大小


make 和makefile (Makefile)

首先make 是一个命令 makefile 是一个文件。

编写makefile 主要注意的是 1.依赖关系2.依赖方法

⮂⮂ buffers 1 mytest:test.c 2 gcc test.c -o mytest 3 4 .PHONY:clean 5 clean: 6 rm -f mytest

.PHONY是伪目标,总是被执行的!!!(总是根据依赖关系执行依赖方法!)通常习惯:clean设置 .PHONY。

[hang@VM-4-14-centos 2]$ clear [hang@VM-4-14-centos 2]$ ls -al total 20 drwxrwxr-x 3 hang hang 4096 Aug 13 17:43 . drwxrwxr-x 3 hang hang 4096 Aug 13 15:44 .. drwxrwxr-x 3 hang hang 4096 Aug 11 18:34 3 -rw-rw-r-- 1 hang hang 74 Aug 13 17:38 makefile -rw-rw-r-- 1 hang hang 72 Aug 13 15:45 test.c [hang@VM-4-14-centos 2]$ make gcc test.c -o mytest [hang@VM-4-14-centos 2]$ ls -al total 32 drwxrwxr-x 3 hang hang 4096 Aug 13 17:43 . drwxrwxr-x 3 hang hang 4096 Aug 13 15:44 .. drwxrwxr-x 3 hang hang 4096 Aug 11 18:34 3 -rw-rw-r-- 1 hang hang 74 Aug 13 17:38 makefile -rwxrwxr-x 1 hang hang 8360 Aug 13 17:43 mytest -rw-rw-r-- 1 hang hang 72 Aug 13 15:45 test.c [hang@VM-4-14-centos 2]$ make make: `mytest' is up to date. [hang@VM-4-14-centos 2]$ make make: `mytest' is up to date.

更新一个新方法

myproc:myproc.cc g++ -o $@ $^ .PHONY:clean clean: rm -rf myproc

$@ 为依赖关系中的目标文件

$^ 为依赖关系中的

如何一次生成多个目标文件呢?

.PHONY:all all: exec mycmd mycmd:mycmd.c gcc -o $@ $^ exec:exec.c gcc -o $@ $^ .PHONY:clean clean: rm -f exec mycmd

如何统一替换呢???

由这样变成这样呢??

在底行模式下

%s/exec/myshell/g

这个东西呢是让我们的编译器编译的时候处于debug模式

mypipe:mypipe.cc g++ -o $@ $^ -std=c++11 #-DDEBUG .PHONY:clean clean: rm -f mypipe

那么makefile是如何得知我的执行程序是最新的呢 ??

根据文件的最近修改时间来确定的

[hang@VM-4-14-centos 2]$ stat mytest File: ‘mytest’ Size: 8360 Blocks: 24 IO Block: 4096 regular file Device: fd01h/64769d Inode: 663575 Links: 1 Access: (0775/-rwxrwxr-x) Uid: ( 1002/ hang) Gid: ( 1002/ hang) Access: 2022-08-13 17:43:23.782275670 +0800 Modify: 2022-08-13 17:43:23.299272903 +0800 Change: 2022-08-13 17:43:23.299272903 +0800 Birth: -

文件 = 属性 + 内容

AMC时间,

a :最近一次打开时间(由于数据存储在磁盘中,频繁的调用就意味着频繁的修改文件,很消耗时间 的,故它有可能会积累到一定的时间进行修改)

m:内容修改时间

c :属性修改时间(内容的修改通常伴随者属性的修改)


mytest:test.o main.o 2 gcc -o mytest test.o main.o 3 test.o:test.c 4 gcc -c test.c -o test.o 5 main.o:main.c 6 gcc -c main.c -o main.o 7 8 9 .PHOYN:clean 10 clean: 11 rm -f mytest

在LInux下,各种 .c 变成了 .o ,然后与 ilbc.so合并链接,形成可执行程序。


缓冲区问题

fflush(stdout) 清空缓存区

#include<stdio.h> 2 #include<unistd.h> 3 4 int main() 5 { 6 printf("hello hang"); 7 sleep(3); 8 return 0; 9 }

这个我们其实发现 hello hang 在三秒之后才出现了。其实printf早早就执行结束了!!只不过信息没有立马显示出来。

#include<stdio.h> 2 #include<unistd.h> 3 4 int main() 5 { 6 printf("hello hang\n"); 7 sleep(3); 8 return 0; 9 }

注意两段代码执行出来的效果,这里面就涉及到了缓冲区的问题。

C语言是会给我们提供缓冲区的,根据特定的刷新策略来进行刷新!!!

显示器设备,一般的刷新策略是行刷新,碰到\n,就把\n 之前的所有字符都显示出来!


值得注意的是

回车和换行本质上是不一样的,具体参考下面的代码。

#include <stdio.h> 2 3 int main() 4 { 5 int i = 3; 6 while( i >= 0 ) 7 { 8 printf("当前是%d\n",i); 9 i--; 10 } 11 12 return 0; 13 }

#include <stdio.h> #include<unistd.h> int main() { int i = 3; while( i >= 0 ) { printf("当前是%d\r",i); i--; fflush(stdout); sleep(1); } return 0; }

\r 就是回到本行的最前面。

进度条代码

#include <stdio.h> #include <string.h> #include <unistd.h> #define NUM 102 int main() { char bar[NUM]; memset(bar, 0 ,sizeof(bar)); const char *lable="|/-\\"; //4符号 int cnt = 0; while(cnt <= 100) { printf("[%-100s][%d%%] %c\r", bar, cnt, lable[cnt%4]); bar[cnt++] = '#'; fflush(stdout); usleep(30000); } printf("\n"); return 0; }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值