程序翻译的过程
文本的C -> 计算机二进制
- 预处理(去注释,宏替换,头文件展开,条件编译...)
- 编译(c ->汇编)
- 汇编(汇编 ->可重定向二进制目标文件)
- 链接(链接多个 .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; }