欢迎来到【web源码解析】【被黑站统计源码】【采集调用直播源码】kfree 源码-皮皮网网站!!!

皮皮网

【web源码解析】【被黑站统计源码】【采集调用直播源码】kfree 源码-皮皮网 扫描左侧二维码访问本站手机端

【web源码解析】【被黑站统计源码】【采集调用直播源码】kfree 源码

2024-11-23 07:24:17 来源:{typename type="name"/} 分类:{typename type="name"/}

1.字符设备中的几个函数分析
2.用C语言写的计算器源代码
3.十大程序编译器?

kfree 源码

字符设备中的几个函数分析

       1.在内核中, dev_t 类型(在 <linux/types.h>中定义)用来持有设备编号 — 主次部分都包括.其中dev_t 是 位的量, 位用作主编号, 位用作次编号

       1 #ifndef _LINUX_TYPES_H

       2 #define _LINUX_TYPES_H

       3

       4 #include <asm/types.h>

       5

       6 #ifndef __ASSEMBLY__

       7 #ifdef __KERNEL__

       8

       9 #define DECLARE_BITMAP(name,bits) /

        unsigned long name[BITS_TO_LONGS(bits)]

       

        #endif

       

        #include <linux/posix_types.h>

       

        #ifdef __KERNEL__

       

        typedef __u __kernel_dev_t;

       

        typedef __kernel_fd_set fd_set;

        typedef __kernel_dev_t dev_t; //用来持有设备编号的主次部分

        typedef __kernel_ino_t ino_t;

        typedef __kernel_mode_t mode_t;

       ...

       2.在 <linux/kdev_t.h>中的一套宏定义. 为获得一个 dev_t 的主或者次编号, 使用:

       2.1设备编号的内部表示

       MAJOR(dev_t dev);

       MINOR(dev_t dev);

       2.在有主次编号时, 需要将其转换为一个 dev_t, 可使用:

       MKDEV(int major, int minor);

       在linux/kdev_t.h中有下了内容

       ...

       4 #define MINORBITS

       5 #define MINORMASK ((1U << MINORBITS) - 1)

       6

       7 #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))

       8 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))

       9 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))//高为表示主设备号,低位表示次设备号

       ...

       3.分配和释放设备编号register_chrdev_region函数

       下面摘自文件fs/char_dev.c内核源代码

        /

**

        * register_chrdev_region() - register a range of device numbers

        * @from: the first in the desired range of device numbers; must include

        * the major number.

        * @count: the number of consecutive device numbers required

        * @name: the name of the device or driver.

       

*

        * Return value is zero on success, a negative error code on failure.

        */

        int register_chrdev_region(dev_t from, unsigned count, const char *name)

        {

        struct char_device_struct *cd;

        dev_t to = from + count; //计算分配号范围中的最大值+=

        dev_t n, next;

       

        for (n = from; n < to; n = next) { /*每次申请个设备号*/

        next = MKDEV(MAJOR(n)+1, 0);/*主设备号加一得到的设备号,次设备号为0*/

        if (next > to)

        next = to;

        cd = __register_chrdev_region(MAJOR(n), MINOR(n),

        next - n, name);

        if (IS_ERR(cd))

        goto fail;

        }

        return 0;

        fail:/*当一次分配失败的时候,释放所有已经分配到地设备号*/

        to = n;

        for (n = from; n < to; n = next) {

        next = MKDEV(MAJOR(n)+1, 0);

        kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));

        }

        return PTR_ERR(cd);

        }

       这里, from是要分配的起始设备编号. from 的次编号部分常常是 0, 但是没有要求是那个效果. count是你请求的连续设备编号的总数. 注意, 如果count 太大, 要求的范围可能溢出到下一个次编号;但是只要要求的编号范围可用, 一切都仍然会正确工作. 最后, name 是应当连接到这个编号范围的设备的名子; 它会出现在 /proc/devices 和 sysfs 中.如同大部分内核函数, 如果分配成功进行, register_chrdev_region 的返回值是 0. 出错的情况下, 返回一个负的错误码, 不能存取请求的区域.

       4.下面是char_device_struct结构体的信息

       fs/char_dev.c

       static struct char_device_struct {

       struct char_device_struct *next; // 指向散列冲突链表中的下一个元素的指针

       unsigned int major; // 主设备号

       unsigned int baseminor; // 起始次设备号

       int minorct; // 设备编号的范围大小

       const char *name; // 处理该设备编号范围内的设备驱动的名称

       struct file_operations *fops; // 没有使用

       struct cdev *cdev; /* will die指向字符设备驱动程序描述符的指针*/

       } *chrdevs[MAX_PROBE_HASH];

        /

*

        * Register a single major with a specified minor range.

       

*

        * If major == 0 this functions will dynamically allocate a major and return

        * its number.

       

*

        * If major > 0 this function will attempt to reserve the passed range of

        * minors and will return zero on success.

       

*

        * Returns a -ve errno on failure.

        */

       /

**

       * 该函数主要是注册注册注册主设备号和次设备号

       * major == 0此函数动态分配主设备号

       * major > 0 则是申请分配指定的主设备号

       * 返回0表示申请成功,返 回负数说明申请失败

       */

        static struct char_device_struct

*

        __register_chrdev_region(unsigned int major, unsigned int baseminor,

        int minorct, const char *name)

        { /*以下处理char_device_struct变量的初始化和注册*/

        struct char_device_struct *cd, **cp;

        int ret = 0;

        int i;

        //kzalloc()分配内存并且全部初始化为0,

        cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);

        if (cd == NULL)

       //ENOMEM定义在include/asm-generic/error-base.h中,

       // #define ENOMEM /* Out of memory */

        return ERR_PTR(-ENOMEM);

       

        mutex_lock(&chrdevs_lock);

       

        /* temporary */

        if (major == 0) { //下面动态申请主设备号

        for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i—) {

       //ARRAY_SIZE是定义为ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

       //#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

       if (chrdevs[i] == NULL)

       //chrdevs是内核中已经注册了的设备好设备的一个数组

        break;

        }

       

        if (i == 0) {

        ret = -EBUSY;

        goto out;

        }

        major = i;

        ret = major;//这里得到一个位使用的设备号

        }

        //下面四句是对已经申请到的设备数据结构进行填充

        cd->major = major;

        cd->baseminor = baseminor;

        cd->minorct = minorct;/*申请设备号的个数*/

        strlcpy(cd->name, name, sizeof(cd->name));

       /*以下部分将char_device_struct变量注册到内核*/

        i = major_to_index(major);

       

        for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)

        if ((*cp)->major > major || //chardevs[i]设备号大于主设备号

        ((*cp)->major == major &&

        (((*cp)->baseminor >= baseminor) || //chardevs[i]主设备号等于主设备号,并且此设备号大于baseminor

        ((*cp)->baseminor + (*cp)->minorct > baseminor))))

        break;

        //在字符设备数组中找到现在注册的设备

        /* Check for overlapping minor ranges. */

        if (*cp && (*cp)->major == major) {

        int old_min = (*cp)->baseminor;

        int old_max = (*cp)->baseminor + (*cp)->minorct - 1;

        int new_min = baseminor;

        int new_max = baseminor + minorct - 1;

       

        /* New driver overlaps from the left. */

        if (new_max >= old_min && new_max <= old_max) {

        ret = -EBUSY;

        goto out;

        }

       

        /* New driver overlaps from the right. */

        if (new_min <= old_max && new_min >= old_min) {

        ret = -EBUSY;

        goto out;

        }

        }

        /*所申请的设备好号能够满足*/

        cd->next = *cp;/*按照主设备号从小到大顺序排列*/

        *cp = cd;

        mutex_unlock(&chrdevs_lock);

        return cd;

        out:

        mutex_unlock(&chrdevs_lock);

        kfree(cd);

        return ERR_PTR(ret);

        }

       以上程序大体上分为两个步骤:

       1.char_device_struct类型变量的分配以及初始化~行

       2.将char_device_struct变量注册到内核,行页到行

       1.char_device_struct类型变量的分配以及初始化

       (1)首先,调用 kmalloc 分配一个 char_device_struct 变量cd。

       检查返回值,web源码解析进行错误处理。

       (2)将分配的char_device_struct变量的内存区清零memset。

       (3)获取chrdevs_lock读写锁,并且关闭中断,禁止内核抢占,write_lock_irq。

       (4)如果传入的主设备号major不为0,跳转到第(7)步。

       (5)这时,major为0,首先需要分配一个合适的被黑站统计源码主设备号。

       将 i 赋值成 ARRAY_SIZE(chrdevs)-1,其中的 chrdevs 是包含有个char_device_struct *类型的数组,

       然后递减 i 的值,直到在chrdevs数组中出现 NULL。当chrdevs数组中不存在空值的时候,

       ret = -EBUSY; goto out;

       (6)到达这里,就表明主设备号major已经有合法的值了,接着进行char_device_struct变量的采集调用直播源码初始化。

       设置major, baseminor, minorct以及name。

       2.将char_device_struct变量注册到内核

       (7)将 i 赋值成 major_to_index(major)

       将major对取余数,得到可以存放char_device_struct在chrdevs中的索引

       (8)进入循环,在chrdevs[i]的链表中找到一个合适位置。

       退出循环的条件:

       (1)chrdevs[i]为空。

       (2)chrdevs[i]的主设备号大于major。

       (3)chrdevs[i]的主设备号等于major,但是html跳转按钮源码次设备号大于等于baseminor。

       注意:cp = &(*cp)->next,cp是char_device_struct **类型,(*cp)->next是一个char_device_struct

*

       类型,所以&(*cp)->next,就得到一个char_device_struct **,并且这时候由于是指针,所以

       对cp赋值,就相当于对链表中的c socket实例源码元素的next字段进行操作。

       (9)进行冲突检查,因为退出循环的情况可能造成设备号冲突(产生交集)。

       如果*cp不空,并且*cp的major与要申请的major相同,此时,如果(*cp)->baseminor < baseminor + minorct,

       就会发生冲突,因为和已经分配了的设备号冲突了。出错就跳转到ret = -EBUSY; goto out;

       ()到这里,内核可以满足设备号的申请,将cd链接到链表中。

       ()释放chrdevs_lock读写锁,开中断,开内核抢占。

       ()返回加入链表的char_device_struct变量cd。

       ()out出错退出

       a.释放chrdevs_lock读写锁,开中断,开内核抢占。

       b.释放char_device_struct变量cd,kfree。

       c.返回错误信息

       下面程序出自fs/char_dev.c

       动态申请设备号

       ...

        /

**

        * alloc_chrdev_region() - register a range of char device numbers

        * @dev: output parameter for first assigned number

        * @baseminor: first of the requested range of minor numbers

        * @count: the number of minor numbers required

        * @name: the name of the associated device or driver

       

*

        * Allocates a range of char device numbers. The major number will be

        * chosen dynamically, and returned (along with the first minor number)

        * in @dev. Returns zero or a negative error code.

        */

        int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,

        const char *name)

        {

       /* dev:

       仅仅作为输出参数,成功分配后将保存已分配的第一个设备编号。

       baseminor:

       被请求的第一个次设备号,通常是0。

       count:

       所要分配的设备号的个数。

       name:

       和所分配的设备号范围相对应的设备名称。

       b.返回值:

       成功返回0,失败返回负的错误编码

       */

        struct char_device_struct *cd;

        cd = __register_chrdev_region(0, baseminor, count, name);

        if (IS_ERR(cd))

        return PTR_ERR(cd);

        *dev = MKDEV(cd->major, cd->baseminor);

        return 0;

        }

       

       ...

用C语言写的计算器源代码

       #include<stdio.h>

       #include<iostream.h>

       #include<stdlib.h>

       #include<string.h>

       #include<ctype.h>

       typedef float DataType;

       typedef struct

       {

        DataType *data;

        int max;

        int top;

       }Stack;

       void SetStack(Stack *S,int n)

       {

        S->data=(DataType*)malloc(n*sizeof(DataType));

        if(S->data==NULL)

        {

        printf("overflow");

        exit(1);

        }

        S->max=n;

        S->top=-1;

       }

       void FreeStack(Stack *S)

       {

        free(S->data);

       }

       int StackEmpty(Stack *S)

       {

        if(S->top==-1)

        return(1);

        return(0);

       }

       DataType Peek(Stack *S)

       {

        if(S->top==S->max-1)

        {

        printf("Stack is empty!\n");

        exit(1);

        }

        return(S->data[S->top]);

       }

       void Push(Stack *S,DataType item)

       {

        if(S->top==S->max-1)

        {

        printf("Stack is full!\n");

        exit(1);

        }

        S->top++;

        S->data[S->top]=item;

       }

       DataType Pop(Stack *S)

       {

        if(S->top==-1)

        {

        printf("Pop an empty stack!\n");

        exit(1);

        }

        S->top--;

        return(S->data[S->top+1]);

       }

       typedef struct

       {

        char op;

        int inputprecedence;

        int stackprecedence;

       }DataType1;

       typedef struct

       {

        DataType1 *data;

        int max;

        int top;

       }Stack1;

       void SetStack1(Stack1 *S,int n)

       {

        S->data=(DataType1*)malloc(n*sizeof(DataType1));

        if(S->data==NULL)

        {

        printf("overflow");

        exit(1);

        }

        S->max=n;

        S->top=-1;

       }

       void FreeStack1(Stack1 *S)

       {

        free(S->data);

       }

       int StackEmpty1(Stack1 *S)

       {

        if(S->top==-1)

        return(1);

        return(0);

       }

       DataType1 Peek1(Stack1 *S)

       {

        if(S->top==S->max-1)

        {

        printf("Stack1 is empty!\n");

        exit(1);

        }

        return(S->data[S->top]);

       }

       void Push1(Stack1 *S,DataType1 item)

       {

        if(S->top==S->max-1)

        {

        printf("Stack is full!\n");

        exit(1);

        }

        S->top++;

        S->data[S->top]=item;

       }

       DataType1 Pop1(Stack1 *S)

       {

        if(S->top==-1)

        {

        printf("Pop an empty stack!\n");

        exit(1);

        }

        S->top--;

        return(S->data[S->top+1]);

       }

       DataType1 MathOptr(char ch)

       {

        DataType1 optr;

        optr.op=ch;

        switch(optr.op)

        {

        case'+':

        case'-':

        optr.inputprecedence=1;

        optr.stackprecedence=1;

        break;

        case'*':

        case'/':

        optr.inputprecedence=2;

        optr.stackprecedence=2;

        break;

        case'(':

        optr.inputprecedence=3;

        optr.stackprecedence=-1;

        break;

        case')':

        optr.inputprecedence=0;

        optr.stackprecedence=0;

        break;

        }

        return(optr);

       }

       void Evaluate(Stack *OpndStack,DataType1 optr)

       {

        DataType opnd1,opnd2;

        opnd1=Pop(OpndStack);

        opnd2=Pop(OpndStack);

        switch(optr.op)

        {

        case'+':

        Push(OpndStack,opnd2+opnd1);

        break;

        case'-':

        Push(OpndStack,opnd2-opnd1);

        break;

        case'*':

        Push(OpndStack,opnd2*opnd1);

        break;

        case'/':

        Push(OpndStack,opnd2/opnd1);

        break;

        }

       }

       int isoptr(char ch)

       {

        if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='(')

        return(1);

        return(0);

       }

       void Infix(char *str)

       {

        int i,k,n=strlen(str);

        char ch,numstr[];

        DataType opnd;

        DataType1 optr;

        Stack OpndStack;

        Stack1 OptrStack;

        SetStack(&OpndStack,n);

        SetStack1(&OptrStack,n);

        k=0;

        ch=str[k];

        while(ch!='=')

        if(isdigit(ch)||ch=='.')

        {

        for(i=0;isdigit(ch)||ch=='.';i++)

        {

        numstr[i]=ch;

        k++;

        ch=str[k];

        }

        numstr[i]='\0';

        opnd= atof(numstr);

        Push(&OpndStack,opnd);

        }

        else

        if(isoptr(ch))

        {

        optr=MathOptr(ch);

        while(Peek1(&OptrStack).stackprecedence>=optr.inputprecedence)

        Evaluate(&OpndStack,Pop1(&OptrStack));

        Push1(&OptrStack,optr);

        k++;

        ch=str[k];

        }

        else if(ch==')')

        {

        optr=MathOptr(ch);

        while(Peek1(&OptrStack).stackprecedence>=optr.inputprecedence)

        Evaluate(&OpndStack,Pop1(&OptrStack));

        Pop1(&OptrStack);

        k++;

        ch=str[k];

        }

        while(!StackEmpty1(&OptrStack))

        Evaluate(&OpndStack,Pop1(&OptrStack));

        opnd=Pop(&OpndStack);

        cout<<"你输入表达式的计算结果为"<<endl;

        printf("%-6.2f\n",opnd);

        FreeStack(&OpndStack);

        FreeStack1(&OptrStack);

       }

       void main()

       {

        cout<<"请输入你要计算的表达式,并以“=”号结束。"<<endl;

        char str[];

        gets(str);

        Infix(str);

       =================================================================

       哈哈!给分吧!

十大程序编译器?

       C++的编译器都有哪些?

       kDevelop、Anjuta、CodeBlocks、VisualMingw、Ideone、EclipseCDT、Compilr、CodeLite、NetbeansC++、Dev?C++。

       Kdevelop是一个专为C/C++及其他语言的开源扩展插件IDE,它基于KDevPlatform平台,这是一款可用于IDE基础开源库。

       AnjutaDevstudio是另外一款强大的开发工具,拥有先进的编程特性包括项目管理、应用程序向导、交互式调试器、源码编辑器、版本控制,GUI设计、分析器等等,这款工具为C/C++开发者提供强大的用户界面接口。

       CodeBlocks是一款比较流行的免费且开源的集成开发环境,该工具拥有所有功能,能够满足开发者所需,比如高效的用户界面、编译及调试功能等。

       Visual-MigGW是一款极为简单的开源IDE,它所有的WindowsAPI都可来进行简单快速的开发,它还支持一个随时可用的应用框架,项目托管在SourceForge.net。

       Ideone是一款在线编辑器和调试工具,这款工具提供了强大的功能,帮助程序员以更加快速有效的方式编译源代码。

       EclipseCDT提供更加高效的功能,如:支持为各种工具链提供项目创建及管理、标准构建、源码导航、各种知识工具源,代码编辑器功能如高亮显示、折叠、超链接导航、源代码重构以及代码生成,可视化调试工具,包括内存、寄存器及反汇编视图。

       Compiler是一款在线集成开发工具,允许你编写令人印象深刻的代码功能和简单的用户界面,该工具支持的语言如C、C++、Java、HTML。

       Codelite是一款极好的免费开源的IDE,几乎可运行于所有平台。

       Netbeans工具包含多种类型模板,它拥有迷人的功能,使其在Web开发者更加流行,比如:代码协助、编译配置、单元测试、源码检测、远程开发及文件导航等功能。

       DevC++的功能包括:类浏览器、集成调试、支持GCC、项目管理、代码编译、编辑且编译资源文件、工具管理、功能清单。

windows的pc端编译器有哪些

       Windows的pc端编译器有:

       1)VisualStudio

       Windows下首先推荐大家使用微软开发的VisualStudio(简称VS),它是Windows下的标准IDE,实际开发中大家也都在使用。为了适应最新的Windows操作系统,微软每隔一段时间(一般是一两年)就会对VS进行升级。VS的不同版本以发布年份命名,例如VS是微软于年发布的,VS是微软于年发布的。

       ä¸è¿‡VS有点庞大,安装包有2~3G,下载不方便,而且会安装很多暂时用不到的工具,安装时间在半个小时左右。

       å¯¹äºŽåˆå­¦è€…,我推荐使用VS。最好不用使用VS,有点坑初学者。

       2)Dev?C++

       å¦‚果你讨厌VS的复杂性,那么可以使用DevC++。DevC++是一款免费开源的C/C++IDE,内嵌?GCC?编译器(LinuxGCC编译器的Windows移植版),是NOI、NOIP?等比赛的指定工具。DevC++的优点是体积小(只有几十兆)、安装卸载方便、学习成本低,缺点是调试功能弱。

       NOI是NationalOlympiadinInformatics的缩写,译为“全国青少年信息学奥林匹克竞赛”;NOIP是NationalOlympiadininformaticsinProvinces的缩写,译为“全国青少年信息学奥林匹克联赛”。NOI、NOIP都是奥林匹克竞赛的一种,参加者多为高中生,获奖者将被保送到名牌大学或者得到高考加分资格。

       3)VisualC++6.0

       VisualC++6.0(简称VC6.0)是微软开发的一款经典的IDE,很多高校都以VC6.0为教学工具来讲解C和C++。但VC6.0是年的产品,很古老了,在Win7、Win8、Win下会有各种各样的兼容性问题,甚至根本不能运行,所以不推荐使用。

       VC6.0早就该扔进垃圾桶了,可是依然有很多大学把它作为教学工具,并且选用的教材也以VC6.0为基础来讲解C语言和C++,可见教学体制的极端落后,课程体系的更新远远跟不上技术的进步。

       4)其它IDE

       é™¤äº†ä¸Šé¢æåˆ°çš„三款IDE,Windows平台下还有很多其他的IDE,它们各有特点,例如:

       Code::Blocks是一款开源、跨平台、免费的C/C++IDE,它和DevC++非常类似,小巧灵活,易于安装和卸载,不过它的界面要比DevC++复杂一些,不如DevC++来得清爽。

       TurboC是一款古老的、DOS年代的C语言开发工具,程序员只能使用键盘来操作TurboC,不能使用鼠标,所以非常不方便。但是TurboC集成了一套图形库,可以在控制台程序中画图,看起来非常炫酷,所以至今仍然有人在使用。

       C-Free是一款国产的Windows下的C/C++IDE,最新版本是5.0,整个软件才M,非常轻巧,安装也简单,界面也比DevC++漂亮。C-Free的缺点也是调试功能弱。可惜的是,C-Free已经多年不更新了,组件都老了,只能在XP、Win7下运行,在Win8、Win下可能会存在兼容性问题。

常见的C语言编译器是什么?

       ç›®å‰æœ€æµè¡Œçš„C语言编译器有以下几种:

       1、GNUCompilerCollection或称?GCC

       GCC(GNUCompilerCollection,GNU编译器套件),是由GNU开发的编程语言编译器。它是以GPL许可证所发行的自由软件,也是GNU计划的关键部分。

       GCC原本作为GNU操作系统的官方编译器,现已被大多数类Unix操作系统(如Linux、BSD、MacOSX等)采纳为标准的编译器,GCC同样适用于微软的Windows。GCC是自由软件过程发展中的著名例子,由自由软件基金会以GPL协议发布。

       2、MicrosoftC或称MSC

       MicrosoftC是c语言的一种IDE(集成开发环境),常见的还有MicrosoftVisualC++,BorlandC++,WatcomC++,BorlandC++,BorlandC++Builder,BorlandC++3.1forDOS,WatcomC++.0forDOS,GNUDJGPPC++,LccwinCCompiler3.1,HighC,TurboC等等......

       3、BorlandTurboC或称TurboC

       TurboC是美国Borland公司的产品,Borland公司是一家专门从事软件开发、研制的大公司。该公司相继推出了一套Turbo系列软件,如TurboBASIC,TurboPascal,TurboProlog,这些软件很受用户欢迎。

       æ‰©å±•èµ„料:

       C编译的整个过程很复杂,大致可以分为以下四个阶段:

       1、预处理阶段在该阶段主要完成对源代码的预处理工作,主要包括对宏定义指令,头文件包含指令,预定义指令和特殊字符的处理,如对宏定义的替换以及文件头中所包含的文件中预定义代码的替换等,总之这步主要完成一些替换工作,输出是同源文件含义相同但内容不同的文件。

       2、编译、优化阶段编译就是将第一阶段处理得到的文件通过词法语法分析等转换为汇编语言。优化包括对中间代码的优化,如删除公共表达式,循环优化等;和对目标代码的生成进行的优化,如如何充分利用机器的寄存器存放有关变量的值,以减少内存访问次数。

       3、汇编阶段将汇编语言翻译成机器指令。

       4、链接阶段链接阶段的主要工作是将有关的目标文件连接起来,即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的目标文件成为一个能够被操作系统装入执行的统一整体。

       å‚考资料来源:百度百科-gcc(GNU编译器套件)

       å‚考资料来源:百度百科-MicrosoftC

       å‚考资料来源:百度百科-TurboC