创建文件hello.c
vim hello.c
测试代码
#include
/* 执行命令: ./hello dengzj
* argc = 2
* argv[0] = ./hello
* argv[1] = dengzj
*/
#define xxx 10
/*argc:argument count argv: argument value*/
int main(int argc, char **argv)
{
if (argc >= 2)
printf("Hello, %s,%d!\n", argv[1],xxx);
else
printf("Hello, world! %d\n",xxx);
return 0;
}
gcc基本用法:gcc [option] [filenames]
编译hello.c文件 不加参数 默认输出
为a.out
gcc hello.c
通常编译hello.c 使用-o参数可命名文件,将hello.c编译后命名为hello,即gcc命令后的-o参数
的位置不固定,带-o参数后面一定接编译后的文件名
。这也是后续编译.c文件使用最多的命令
。结果如下图所示
gcc hello.c -o hello
//或者
gcc -o hello hello.c
以上是学习中大多数时候使用的gcc编译指令,上面代码是一步到位的得到链接后的文件,其本质是要经过预处理 编译 汇编 链接这四步。即下面的4行指令依次完成
gcc -E -o hello.i hello.c
gcc -S -o hello.s hello.i
gcc -c -o hello.o hello.s
gcc -o hello hello.o
最开始编写的hello.c文件变为hello.i
文件, 展开宏、头文件,替换条件编译,删除注释、空行、空白。
gcc -E -o hello.i hello.c
打开文件里面就是一些头文件路径即展开宏。打开hello.i文件,在一般模式下输入/main后会看见源代码的xxx宏已经展开后得到数值为10。
.i文件编译得到汇编形式的hello.s
,检测语法规范,消耗时间、系统资源最多。同样用vim 打开文件可查看到汇编形式的代码。
gcc -S -o hello.s hello.i
同理,灵活使用,可将上面融合为一步。gcc -S -o hello.s hello.c,可直接将hello.c文件编译为汇编形式,并命名为hello.s
。
得到hello.o文件,将汇编指令翻译成机器指令,进入则看到的是一堆机器码。
gcc -c -o hello.o hello.s
数据段合并 将生成的.obj文件与库文件.lib等文件链接,生成可执行文件(.exe文件) ,地址回填。
将hell.o和库文件、系统文件的一系列.o文件进行链接。
gcc -o hello hello.o
查看gcc完整编译过程,带-v参数,输出结果复制到Notepad++打开
gcc -o hello hello.o -v
vim main.c
#include
#include "sub.h"
int main(int argc, char *argv[])
{
int i;
printf("Main fun!\n");
sub_fun();
return 0;
}
vim sub.c
void sub_fun(void)
{
printf("Sub fun!\n");
}
vim sub.h
void sub_fun(void);
一条命令,处理多个源文件。以此类推,10个文件编写,在后面加10个文件名即可。实际工程中,文件一多起来就不行了(需要makefile),因此gcc的缺点是对所有文件都需要再一次处理
。
gcc -o test main.c sub.c
当多文件(比如100个文件)进行编译,其中一个文件需要修改时,因为只是某些修改文件的内容,而后其余文件却要被重新处理一次,使用上面这条命令就显得很浪费时间。因此可以使用-c
命令只进行前三个步骤(预处理、编译、汇编),最后再统一链接。
即:
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o
这样在只修改某些文件时,只需要执行对应的-c命令即可。
main.c的头文件中,<>代表在系统目录或工具链的默认的指定路径目录下查找,编译时加上-v选项可查看, ""代表在当前目录下查找文件。
利用-I来指定目录,修改mian.c 该为
#include
#include
int main(int argc, char *argv[])
{
int i;
printf("Main fun!\n");
sub_fun();
return 0;
}
gcc -c -o main.o main.c -I ./
每个需要使用静态库的程序都要将整个静态库编译到可执行程序中,若静态库50M,10个程序要500M。
库函数本地化,优点调用速度快
,缺点是系统资源消耗大
,多用于对时间要求较高的核心程序。
未链接sub.c文件,文件编译时可以将其他文件生成.o文件制作成库来使用
ar rcs lib库名.a 一系列.o文件
解决办法:当然可以在代码后加入sub.c文件进行链接生成test文件
或者制作静态库,先生成sub.o文件。
gcc -c -o sub.o sub.c
制作静态库
ar crs libsub.a sub.o
使用静态库
gcc -o test main.o libsub.a
机制:多个可执行程序共享一份库文件(共享代码、不共享数据)。
使用 gcc -shared 制作动态库。
gcc -shared -o lib库名.so add.o sub.o div.o
制作动态库
gcc -shared -o libsub.so sub.o
使用动态库1
gcc -o test2 main.o libsub.so
链接可执行程序时,指定所使用的动态库, -l:指定动态库名 -L:指定动态库路径。
使用动态库2
gcc -o test2 main.o -L./ -lsub
运行时,需要添加动态指定路径,:./
添加当前路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
./test2
总结:
1、动态库是否加载到内存,取决于程序是否运行
2、动态库每次加载的位置不固定
3、动、静态库共存时,编译器默认使用动态库
查看c.c文件的依赖
gcc -M c.c
利用-MF指令生成名为c.e的依赖文件
gcc -M -MF c.e c.c
gcc -c -o c.o c.c -MD -MF c.e