优秀网站首页承接各类网站建设

当前位置: 首页 > news >正文

优秀网站首页,承接各类网站建设,wordpress导出用户,再网站里做商家店铺目录 1. 举例 2.预处理 2.1 预处理命令 2.2 .i文件内容解读 3.编译 4.汇编 5.链接 5.1 链接方式 5.1.1 静态链接 5.1.2 动态链接 5.1.3 混合链接 1. 举例 Linux的C语言开发#xff0c;一般选择GCC工具链进行编译#xff0c;通过下面的例子来演示GCC如何使用#…目录 1. 举例 2.预处理 2.1 预处理命令 2.2 .i文件内容解读 3.编译 4.汇编 5.链接 5.1 链接方式 5.1.1 静态链接 5.1.2 动态链接 5.1.3 混合链接 1. 举例 Linux的C语言开发一般选择GCC工具链进行编译通过下面的例子来演示GCC如何使用 main.c #include hello.hint main() {say_hello();return 0; }hello.h #ifndef HELLO_H #define HELLO_Hvoid say_hello();#endifhello.c #include hello.h #include stdio.hvoid say_hello() {printf(Hello world!\n); }采用如下命令编译可执行文件并执行 gcc main.c hello.c -o main // 编译 ./main // 运行程序 -ooutput的缩写表示输出用于指定输出文件名。 2.预处理 2.1 预处理命令 在C语言编译过程中预处理是其中的第一个阶段它的主要目的是处理源代码文件中的预处理指令将它们转换成编译器可以识别的形式。预处理主要包含宏替换、文件包含、条件编译、注释移除等几种任务。预处理的输出通常是经过预处理后的源代码文件它会被保存成一个临时文件并作为编译器的输入。预处理器处理后的文件通常会比原始源文件大因为它会展开宏和包含其他文件的内容。 命令格式如下 gcc -E main.c -o main.i -EExpand展开的缩写该参数指定gcc执行预处理操作。.iintermediate中间的的缩写预处理后的源文件通常以.i作为后缀。 得到的main.i就是预处理之后的文件。我们可以查看内容:

0 main.c

0 built-in

0 command-line

1 /usr/include/stdc-predef.h 1 3 4

0 command-line 2

1 main.c

1 hello.h 1void say_hello();

2 main.c 2int main()

{say_hello();return 0; }2.2 .i文件内容解读 处理后的.i文件包含了经过C预处理器处理的源代码及行控制指令等内容。 .i文件中以#开头的是预处理器插入的行控制指令用于标示从下一行起的代码来源格式大致为

行号 文件名 标志

行号和文件名表示从下一行开始的源代码来源于哪个文件的哪一行。 标志可以是数字1,2,3,4每个数字的含义如下 1: 表示接下来的内容开始于一个新的文件。2: 表示控制权从被包含的文件返回。这用于当预处理器完成一个包含文件的读取回到包含它的文件继续处理时。3: 指示接下来的内容来自系统头文件。4: 表明接下来的内容应被视为被extern C包围这主要用于C中以指示C链接约定。extern C是C中的关键字组合我们不必关注。 注行号为0通常是预处理器的一种特殊标记用法并不指向源代码中的实际行号。它可能用于初始化或特殊标记比如标识文件的开始而不直接对应于源代码中的行。 3.编译 编译阶段编译器会将经过预处理的源代码文件转换成汇编代码。在这个阶段编译器会将源代码翻译成机器能够理解的中间代码包括词法分析、语法分析、语义分析和优化等过程。编译器会检查代码的语法和语义生成对应的汇编代码。编译阶段是整个编译过程中最复杂和耗时的阶段之一它对源代码进行了深入的分析和转换确保了程序的正确性和性能。 格式如下 gcc -S main.i -o main.s -SSource源代码的缩写该参数指定gcc将预处理后的源码编译为汇编语言。.sAssembly Source汇编源码的缩写通常编译后的汇编文件以.s作为后缀。 4.汇编 汇编阶段是C语言编译过程中的重要阶段它将编译器生成的中间代码或汇编代码转换成目标机器的机器语言代码也就是目标代码。这个阶段由汇编器Assembler完成其主要任务是将汇编指令翻译成目标机器的二进制形式。主要包含以下几个任务符号解析、指令翻译、地址关联、重定位、代码优化。最终汇编器会将翻译和处理后的目标代码输出到目标文件中用于后续的链接和生成可执行程序或共享库文件。 格式如下 gcc -c main.s -o main.o -c可以被理解为Compile or Assemble编译或汇编该参数可以指定gcc将汇编代码翻译为机器码但不做链接。此外该参数也可以用于将.c文件直接处理为机器码同样不做链接。-oObject的缩写通常汇编得到的机器码文件以.o为后缀。 5.链接 链接阶段由链接器完成。链接器将各个目标文件以及可能用到的库文件进行链接生成最终的可执行程序。在这个阶段链接器会解析目标文件中的符号引用并将它们与符号定义进行匹配以解决符号的地址关联问题。链接器还会处理全局变量的定义和声明解决重定位问题最终生成可执行文件或共享库文件。 5.1 链接方式 我们在say_hello()函数中调用了printf()函数这个函数是在stdio.h中声明的后者来源于glibc库printf()的实现在glibc的二进制组件中通常是在共享库如libc.so或静态库如libc.a文件中。因此我们除了要链接main.o、hello.o还需要和glibc库的文件链接。通常C语言的链接共有三种方式静态链接、动态链接和混合链接。三者的区别就在于链接器在链接过程中对程序中库函数调用的解析。 5.1.1 静态链接 将所有目标文件和所需的库在编译时一并打包进最终的可执行文件。库的代码被复制到最终的可执行文件中使得可执行文件变得自包含不需要在运行时查找或加载外部库。 格式如下 gcc -static main.o hello.o -o main -static该参数指示编译器进行静态链接而不是默认的动态链接。使用这个参数GCC会尝试将所有用到的库函数直接链接到最终生成的可执行文件中包括C标准库libc、数学库libm和其他任何通过代码引用的外部库。 5.1.2 动态链接 库在运行时被加载可执行文件包含了需要加载的库的路径和符号信息。动态链接的可执行文件比静态链接的小因为它们共享系统级的库代码。与静态链接不同库代码不包含在可执行文件中。 方式一 gcc main.o hello.o -o main 没有添加-static关键字gcc默认执行动态链接即glibc库文件没有包含到可执行文件中。 方式二 执行下面的指令将hello.o编译为动态链接库libhello.so。 gcc -fPIC -shared -o libhello.so hello.o -fPIC这个选项告诉编译器为“位置无关代码Position Independent Code”生成输出。在创建共享库时使用这个选项是非常重要的因为它允许共享库被加载到内存中的任何位置而不影响其执行。这是因为位置无关代码使用相对地址而非绝对地址进行数据访问和函数调用使得库在被不同程序加载时能够灵活地映射到不同的地址空间。-shared这个选项指示GCC生成一个共享库而不是一个可执行文件。共享库可以被多个程序同时使用节省了内存和磁盘空间。-o libhello.so这部分指定了输出文件的名称。-o选项后面跟着的是输出文件的名字这里命名为libhello.so。按照惯例Linux下的共享库名称以lib开头扩展名为.so表示共享对象。hello.o这是命令的输入文件即之前编译生成的目标文件。在这个例子中GCC会将hello.o中的代码和数据打包进最终的共享库libhello.so中。 上述命令的作用是使用GCC采用位置无关代码的方式从hello.o目标文件创建一个名为libhello.so的动态共享库文件。 使用动态链接库编译新的可执行文件 gcc main.o -L ./ -lhello -o main_d -L ./指定了库文件搜索路径。-L选项告诉链接器在哪些目录下查找库文件./表示当前目录。这意味着在链接过程中链接器将会在当前目录下搜索指定的库文件。-lhello指定了要链接的库。-l选项后面跟库的名称这里是hello。根据约定链接器会搜索名为libhello.so动态库或libhello.a静态库的文件来链接。链接器会根据-L选项指定的路径列表查找这个库。 这时如果我们直接执行main_d文件会收到以下报错 ./main_d: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory 这句报错的意思时main_d在执行过程中没有找到动态链接库文件libhello.so文件链接失败无法执行。Linux的默认动态链接库文件夹是/lib 和/usr/lib而我们的libhello.so不在其中所以我们需要在执行的时候指明额外的动态链接库文件夹。 解决方式 将libhello.so放入/lib 和/usr/lib中(不推荐) 添加临时路径格式如下 LD_LIBRARY_PATH/home/hello/helloworld ./main_d 5.1.3 混合链接 某些库静态链接而其他库动态链接。这种方式结合了静态链接和动态链接的优点。 执行下面的指令可以将hello.o编译为静态链接库libhello.a ar crv libhello.a hello.o ar归档命令用于处理静态库文件。crvar命令的选项由三个字符组成每个字符代表一个选项c创建归档文件。如果指定的归档文件不存在ar会创建它。r替换归档文件中现有的文件或者向归档文件中添加新文件。如果hello.o已经在libhello.a中它会被新版本替换如果不存在则会被添加。v详细模式verbose mode在处理文件时显示详细信息。使用这个选项ar会列出它正在执行的操作包括哪些文件被添加或替换。libhello.a要创建或更新的静态库文件的名称。按照惯例Linux下的静态库文件名以lib开头并以.a作为文件扩展名。hello.o输入文件即要添加到静态库libhello.a中的目标文件。此处只有一个目标文件hello.o但ar命令支持同时指定多个文件。 利用静态库文件生成可执行的main文件 gcc main.o -L ./ -lhello -o main -L ./表示额外的库文件位置为当前目录-lhello表示链接libhello.a文件。注意这里要去掉开头的lib前缀和结尾的.a后缀。 编译完成后的main文件同样可以执行并且不依赖于静态库libhello.a。 注意如果相同目录下同时存在hello的静态库和动态库文件链接时会默认选择动态链接。