编译器背后的故事

本文深入探讨了编译器的工作原理,从创建静态库.a和动态库.so,到如何使用gcc链接生成可执行程序。通过实例比较了静态库和动态库在程序大小上的差异,并介绍了Linux环境下C语言编译实现贪吃蛇游戏的过程。同时,文章还涉及到第三方库如ncurses的使用及其在Linux系统中的位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.可执行程序是如何被组装的

1.1(2)用gcc生成静态库和动态库

第 1 步:编辑生成例子程序 hello.h、hello.c 和 main.c。
创建一个作业目录:

在这里插入图片描述在这里插入图片描述

//程序 1: hello.h 
#ifndef HELLO_H 
#define HELLO_H 
void hello(const char*name); 
#endif//HELLO_H
//程序 2: hello.c 
#include<stdio.h> 
void hello(const char*name) 
{ 
printf("Hello%s!\n",name);
 }
//程序 3: main.c 
#include"hello.h" 
int main() 
{ 
hello("everyone");
return 0;
 }

第 2 步:将 hello.c 编译成.o 文件
在这里插入图片描述
第 3 步:由.o 文件创建静态库
在这里插入图片描述
第 4 步:在程序中使用静态库
在这里插入图片描述第 5 步:由.o 文件创建动态库文件
在这里插入图片描述
第 6 步:在程序中使用动态库
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述如果是用的ubuntu16.04,则需要用gcc -fPIC -c hello.c命令生成hello.o再执行gcc -shared-fPIC-olibmyhello.sohello.o

1.1(2)静态库.a与.so库文件的生成与使用

静态库.a 文件的生成与使用
在这里插入图片描述在这里插入图片描述
代码:

//A1.c:
#include <stdio.h> 
void print1(int arg)
{ 
printf("A1 print arg:%d\n",arg); 
}
//A2.c:
#include <stdio.h> 
void print2(char *arg)
{ 
printf("A2 printf arg:%s\n", arg); 
}
//A.h
#ifndef A_H 
#define A_H 
void print1(int); 
void print2(char *);
 #endif
//test.c:
#include <stdlib.h> 
#include "A.h" 
int main()
{ 
 print1(1);
 print2("test"); 
 exit(0); 
 }

共享库.so 文件的生成与使用

在这里插入图片描述在这里插入图片描述

1.2用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序,记录文件的大小。

main函数代码将调用x2x和x2y ;将这3个函数分别写成单独的3个 .c文件,并用gcc分别编译为3个.o 目标文件;将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件, 然后用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序,记录文件的大小。
在这里插入图片描述在这里插入图片描述在这里插入图片描述

$ vim sub1.c//编辑sub1.c文件
$ vim sub2.c//编辑sub2.c文件
$ vim main1.c//编辑main1.c文件
$ gcc sub1.c//编译sub1.c文件文件
$ gcc sub2.c//编译sub2.c文件文件
$ gcc main1.c//编译main1.c,sub1.c和sub2.c文件文件
$ ar -crv libmain1.a sub1.o sub2.o   //生成静态文件库
$ gcc main1.c libmain1.a -o result    //mian1.c与静态文件库连接
$ ./result//执行当前目录下的result的文件,‘./’是当前目录的意思

*代码:

//sub1.c
#include<stdio.h>
float x2x(float a,float b)
{
return a+b;//返回a+b的值
}
//sub2.c
#include<stdio.h>
float x2y(float a,float b)
{
return a*b;//返回a+b的值
}
//main1.c
#include"sub1.c"//引用sub1.c文件
#include"sub2.c"//引用sub2.c文件
#include<stdio.h>
float main()
{
float a=2,b=3;//定义
printf("%f",x2x(a,b));//输出x2x(a,b)的值
printf("%f",x2y(a,b));//输出x2y(a,b)的值
return 0;
}

1.3将x2x、x2y目标文件用 ar工具生成1个 .so 动态库文件, 然后用 gcc将 main函数的目标文件与此动态库文件进行链接,生成最终的可执行程序,记录文件的大小,并与之前做对比。

在这里插入图片描述

$ gcc -shared -fPIC -o libmain1.so sub1.o sub2.o    //生成动态文件库
$ gcc main1.c libmain1.so -o result       //与动态文件库连接

对比可得,动态库文件比静态库文件更大。

2.每一个程序背后都站着一堆优秀的代码库。了解实际程序是如何借助第三方库函数完成代码设计。

2.1(1)GCC编译器背后的故事

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

2.1(2)Linux GCC常用命令

在这里插入图片描述在这里插入图片描述在这里插入图片描述

2.2在ubuntu中下载安装nasm,对示例代码“hello.asm”编译生成可执行程序,并与“hello world”C代码的编译生成的程序大小进行对比。

用$ sudo apt-get install nasm安装nasm:
在这里插入图片描述
用$ nasm -version查看是否安装成功:
在这里插入图片描述
编译生成可执行程序:
在这里插入图片描述
nasm生成的程序大小:
在这里插入图片描述
c语言生成的程序大小:
在这里插入图片描述
对比可知nasm编译得到的文件大小要比用gcc编译得到的文件大小要小很多。
代码:

; hello.asm 
section .data            ; 数据段声明
        msg db "Hello, world!", 0xA     ; 要输出的字符串
        len equ $ - msg                 ; 字串长度
section .text            ; 代码段声明
global _start            ; 指定入口函数
_start:                  ; 在屏幕上显示一个字符串
        mov edx, len     ; 参数三:字符串长度
        mov ecx, msg     ; 参数二:要显示的字符串
        mov ebx, 1       ; 参数一:文件描述符(stdout) 
        mov eax, 4       ; 系统调用号(sys_write) 
        int 0x80         ; 调用内核功能
                         ; 退出程序
        mov ebx, 0       ; 参数一:退出代码
        mov eax, 1       ; 系统调用号(sys_exit) 
        int 0x80         ; 调用内核功能

3. 每一个程序背后都站着一堆优秀的代码库。了解实际程序是如何借助第三方库函数完成代码设计。

3.1了解Linux 系统中终端程序最常用的光标库(curses)的主要函数功能,写出几个基本函数名称及功能。

cbreak():调用cbreak函数后,除了"Del"和"Ctrl"键外,接受其他所有字符输入。
noecho()/echo():关闭/打开输入回显功能。
nl ()/nonl():输出时,换行是否作为回车字符。nl函数将换行作为回车符,而nonl函数相反。

3.2以游客身份体验一下即将绝迹的远古时代的 BBS

**加粗样式**
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
打开cmd命令窗口输入 telnet bbs.newsmth.net进入bbs

3.3在Ubuntu中用 sudo apt-get install libncurses5-dev 安装curses库,请说明 头文件(比如curses.h)和库文件都被安装到哪些目录中。

在这里插入图片描述

curses函数库的头文件安装在/usr/include/下,curses函数库的库文件安装在/usr/lib/下

4.Linux 环境下C语言编译实现贪吃蛇游戏

复制代码到ubuntu下,并保存为mysnake1.0.c
链接:http://www.linuxidc.com/Linux/2011-08/41375.htm

打开终端输入
在这里插入图片描述
如下图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值