赞
踩
目录
大小写切换
不退出vim执行命令
gcc
是GNU Compiler Collection(GNU编译器集合)的缩写,是一个广泛使用的编程工具,用于编译和链接C、C++、Objective-C和其他语言的源代码。
gcc
主要用于将高级编程语言(如C、C++等)的源代码转换为可执行文件或库文件。它执行以下主要任务:
编译:gcc
将源代码文件(如.c
、.cpp
等)编译为机器代码文件(如.o
、.obj
等)。编译过程将源代码转换为汇编语言,然后再转换为机器代码。
链接:gcc
将编译生成的目标文件(.o
、.obj
等)以及所需的库文件链接在一起,生成最终的可执行文件或库文件。链接过程将解析和解决符号引用,将多个目标文件和库文件组合成一个完整的可执行文件。
除了编译和链接源代码,gcc
还提供了许多选项和功能,用于优化代码、调试程序、生成调试信息、处理预处理指令等。
格式 gcc [选项] 要编译的文件 [选项] [目标文件]
libc.so.6
的库文件中。/usr/lib
)下查找这个库文件。通过链接到libc.so.6
,程序能够实现对“printf”等函数的调用,这就是链接阶段的作用。在Linux系统中,库文件主要有两种形式:动态库(.so
文件)和静态库(.a
文件)。相应地,在Windows系统中,这两种类型的库文件分别以.dll
(动态库)和.lib
(静态库)作为后缀名。
静态库在编译链接过程中,将库文件中的代码全部加入到生成的可执行文件中。这种方式会导致可执行文件体积较大,但好处是运行时不再依赖外部的库文件。静态库文件在Linux中一般以.a
作为后缀名。
动态库的处理方式则不同,它在编译链接时不会将库文件的代码直接加入到可执行文件中。
.so
,例如之前提到的libc.so.6
便是一个动态库。file
命令来验证。例如,编译生成可执行文件的命令可以是:gcc hello.o -o hello
,这里GCC会默认链接到动态库。要使用Makefile,您可以按照以下步骤进行:
1. 创建Makefile文件:在项目的根目录或适当的位置创建一个名为“Makefile”(或“makefile”)的文件。
2. 定义目标和规则:在Makefile中,定义您的目标和相应的规则。每个目标表示一个输出文件,而规则则指定如何生成目标。
- target: dependencies//依赖关系
- command//依赖方法
例如,如果您有一个C程序(如“hello.c”)需要编译成可执行文件(如“hello”),Makefile可能如下所示:
- hello: hello.o
- gcc hello.o -o hello
-
- hello.o: hello.c
- gcc -c hello.c -o hello.o
3. 运行make命令:在命令行中,进入到包含Makefile的目录,并运行`make`命令。
make
这将根据Makefile中的规则自动构建项目。
这样,Makefile就会根据定义的规则构建和管理您的项目。这对于大型项目和多文件项目的构建过程特别有用。
- hello: hello.o
- gcc hello.o -o hello
-
- hello.o: hello.s
- gcc -c hello.s -o hello.o
-
- hello.s: hello.i
- gcc -S hello.i -o hello.s
-
- hello.i: hello.c
- gcc -E hello.c -o hello.i
-
- .PHONY:clean
- clean:
- rm -f hello.i hello.s hello.o hello
touch
命令模拟),Make将执行相应的命令来生成“hello”文件。Make的核心在于管理文件之间的依赖关系。它会一步步地检查和满足这些依赖,直到达到最终的构建目标。如果在解析依赖的过程中遇到无法找到的文件,Make会停止并报错。然而,对于命令执行错误或编译失败,Make不会中断其过程,因为它主要关注的是文件依赖性。
总结来说,Make通过逐层解析和满足文件依赖,自动化地管理编译过程。这种方式极大地简化了复杂项目的构建过程,使开发者能够专注于代码开发,而不是构建过程的每一个细节。
工程是需要被清理的。
例: 链接三个文件
其中makefile如下:
- [hbr@VM-16-9-centos lesson5]$ cat makefile
- mytest:test.o main.o
- gcc -o mytest test.o main.o
- test.o:test.c
- gcc -c test.c -o test.o
- main.o:main.c
- gcc -c main.c -o main.o
-
- .PHONY:clean
- clean:
- rm -f *.o mytest
- [hbr@VM-16-9-centos program1]$ touch test.c
- [hbr@VM-16-9-centos program1]$ vim test.c
- [hbr@VM-16-9-centos program1]$ cat test.c
- #include <stdio.h>
- #include <unistd.h>
-
- int main()
- {
- printf("hello\n");
- sleep(3);
- return 0;
- }
- [hbr@VM-16-9-centos program1]$ gcc test.c
- [hbr@VM-16-9-centos program1]$ ls
- a.out makefile proc proc.c test.c
- [hbr@VM-16-9-centos program1]$ ./a.out
- hello
- [hbr@VM-16-9-centos program1]$ vim test.c
- [hbr@VM-16-9-centos program1]$ cat test.c
- #include <stdio.h>
- #include <unistd.h>
-
- int main()
- {
- printf("hello");
- sleep(3);
- return 0;
- }
- [hbr@VM-16-9-centos program1]$ gcc test.c
- [hbr@VM-16-9-centos program1]$ ./a.out
第一次输出时:先输出Hello然后3秒后结束。
第二次去掉“\n”输出时:先等待三秒然后输出Hello后结束。
当第一次执行编译后的程序时,程序会立即输出"hello",然后等待3秒钟后结束。这是因为printf
函数遇到换行符\n
时,会立即刷新输出缓冲区,使得"hello"紧接着被输出到屏幕上。
而在第二次执行时,由于从printf
的字符串中移除了换行符\n
,输出的行为有所不同。
printf
输出的"hello"首先被存储在输出缓冲区中,并不会立即显示。\n
时进行刷新。\n
后,"hello"会在等待了3秒后才显示出来的原因。\n换行本质上是:换行(到下一行)+回车(到行首),先看代码。
- [hbr@VM-16-9-centos program1]$ vim test.c
- [hbr@VM-16-9-centos program1]$ cat test.c
- #include <stdio.h>
- #include <unistd.h>
-
- int main()
- {
- int n = 6;
- while(n >= 0)
- {
- printf("n=%d\n",n);
- n--;
- sleep(1);
- }
- return 0;
- }
- [hbr@VM-16-9-centos program1]$ gcc test.c
- [hbr@VM-16-9-centos program1]$ ./a.out
- n=6
- n=5
- n=4
- n=3
- n=2
- n=1
- n=0
- [hbr@VM-16-9-centos program1]$ vim test.c //\n换成\r
- [hbr@VM-16-9-centos program1]$ gcc test.c
- [hbr@VM-16-9-centos program1]$ ./a.out //没有输出结果
- [hbr@VM-16-9-centos program1]$ vim test.c
- [hbr@VM-16-9-centos program1]$ cat test.c
- #include <stdio.h>
- #include <unistd.h>
-
- int main()
- {
- int n = 6;
- while(n >= 0)
- {
- printf("n=%d\r",n);
- n--;
- fflush(stdout);
- sleep(1);
- }
- return 0;
- }
- [hbr@VM-16-9-centos program1]$ gcc test.c
- [hbr@VM-16-9-centos program1]$ ./a.out
- [hbr@VM-16-9-centos program1]$//会按照倒计时输出,此处不方便展示效果
\n
用于在每次输出后换行并回到行首,这是标准的行为,使得每个输出结果都在新的一行显示,因此可以看到从n=6
递减到n=0
的过程,每个数字都在新的一行上。\n
替换为\r
时,行为发生了变化。在计算机中,\r
是回车符,它的作用是将光标移回行首,但不会进入新行。这意味着如果只用\r
而不是\n
,所有的输出都会在同一行上发生,而且后面的输出会覆盖前面的输出。fflush(stdout);
的情况下,由于输出缓冲区不会因\r
而刷新,可能在程序执行完毕之前看不到任何输出。这是因为输出缓冲区通常在满了或者程序结束时才会自动刷新,导致在第二次尝试中看不到输出结果。fflush(stdout);
后,每次调用printf
之后立即强制刷新输出缓冲区,使得即使是\r
也能即时看到效果。这导致光标回到行首,然后用新的数字覆盖旧的数字,实现了一个简单的倒计时效果。因为光标每次都回到行首,而且立即刷新,所以你可以看到n
的值从6递减到0,但这个过程中你只会在屏幕上看到一个数字的变化,而不是多行输出。该程序的可视化效果是一个逐步填充的进度条,旁边有一个旋转的符号表示进度正在进行,直到进度条完全填满,并显示100%。通过这种方式,可以在执行较长时间的操作时给用户一个视觉上的反馈。
- [hbr@VM-16-9-centos program1]$ tree
- .
- ├── makefile
- ├── proc.c
- └── test.c
-
- 0 directories, 3 files
- [hbr@VM-16-9-centos program1]$ cat makefile
- proc:proc.c
- gcc -o proc proc.c
-
- .PHONY:clean
- clean:
- rm -f proc
- [hbr@VM-16-9-centos program1]$ vim proc.c
- [hbr@VM-16-9-centos program1]$ cat proc.c
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #define NUM 51
-
- int main()
- {
- char bar[NUM];
- memset(bar,0,sizeof(bar));
- const char *lable="|/-\\";
- int i=0;
- while(i<=50)
- {
- printf("[%-50s][%d%%] %c\r",bar,i*2,lable[i%4]);
- bar[i++]='#';
- fflush(stdout);
- usleep(30000);
- }
- printf("\n");
- return 0;
- }
- [hbr@VM-16-9-centos program1]$ make
- gcc -o proc proc.c
- [hbr@VM-16-9-centos program1]$ ls
- makefile proc proc.c test.c
- [hbr@VM-16-9-centos program1]$ ./proc
- [##################################################][100%] -
在proc.c
中,定义了一个进度条,使用字符数组bar
来模拟进度条的填充情况,并通过循环逐渐增加bar
数组中的#
字符数量来表示进度的增加。下面是代码的逐行解释:
stdio.h
(用于输入输出)、string.h
(用于内存操作),和unistd.h
(用于usleep
函数,暂停执行)。NUM
为51,这个值用于定义字符数组bar
的长度。main
函数中,声明字符数组bar
并通过memset
函数将其初始化为全0,这意味着开始时进度条是空的。lable
,包含四个字符"|/-\\"
,用于在进度条旁边显示旋转的效果,模仿一个正在进行的操作。while
循环,条件为i
小于等于50,这意味着进度条的最大填充长度为50个#
字符。printf
函数打印进度条。[%-50s]
用于左对齐打印字符串bar
,宽度固定为50个字符;[%d%%]
显示当前进度的百分比,因为循环是到50,所以用i*2
来计算百分比;%c
用于打印旋转符号,通过lable[i%4]
选择"|/-\\"
中的一个字符,随着i
的增加而变化。bar[i]
设置为#
,通过递增i
来模拟进度条的填充。fflush(stdout)
强制刷新标准输出,确保每次循环的输出都能立即显示而不是等缓冲区满。usleep(30000)
暂停30毫秒(30000微秒),这样用户可以看到进度条的逐步填充和旋转符号的动态变化。\n
,以避免在命令行提示符出现之前光标停留在进度条的末尾。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。