广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言 超详细讲解链接器
  • 319
分享到

C语言 超详细讲解链接器

2024-04-02 19:04:59 319人浏览 独家记忆
摘要

目录1 什么是链接器2 声明与定义3 命名冲突3.1 命名冲突3.2 static修饰符4 形参、实参、返回值5 检查外部类型6 头文件1 什么是链接器 典型的链接器把由编译器或汇编

1 什么是链接器

典型的链接器把由编译器或汇编器生成的若干个目标模块,整合成一个被称为载入模块或可执行文件的实体–该实体能够被操作系统直接执行。

截图

链接器通常把目标模块看成是由一组外部对象组成的。每个外部对象代表着机器内存中的某个部分,并通过一个外部名称来识别。因此,==程序中的每个函数和每个外部变量,如果没有被声明为static,就都是一个外部对象。==某些C编译器会对静态函数和静态变量的名称做一定改变,将它们也作为外部对象。由于经过了“名称修饰”,因此它们不会与其它源程序文件中的同名函数或同名变量发生命名冲突。

2 声明与定义


extern int a;

上面的这段代码并不是对a的定义,而是说明a是一个外部整型变量。

注意:引入之后,假如引入的位置在函数之外,就相当于在那个位置定义了全局变量,同样遵循局部变量优先原则,如果引入位置在某个函数之内,就相当于是一个局部变量,作用域与那个地方定义的局部变量相类似,此处讨论声明周期没有任何意义。


int a;
extern int a;

上面的这两条语句既可以是在同一个源文件中,也可以位于程序的不同源文件之中。

==注意:每个外部变量只能定义一次。==如果外部变量的多个定义各指定一个初始值,例如:


int a = 7;

出现在一个源文件中,而


int a = 9;

出现在另一个源文件中,大多数系统都会拒绝接收该程序。但是,如果一个外部变量在多个源文件中定义却没有指定初始值,那么**某些系统会接受这个程序,而另外一些系统则不会接受。**所以,每个外部变量必须只定义一次。

3 命名冲突

3.1 命名冲突

如果在两个不同的源文件中都包括了定义


int a;

那么它要么表示程序错误(如果链接器进制外部变量重复命名的话),要么在两个源文件中共享a的同一个实例(无论两个源文件中的外部变量是否应该被共享)。即使其中a的一个定义是出现在系统提供的库文件中,也仍然进行同样的处理。

3.2 static修饰符


static int a;

static修饰a之后,a的作用域将被限制在一个源文件中,对于其它源文件,a是不可见的,且无法再被extern所引用,当然,static也适用于函数。使用static之后,我们就可以在其它的源文件中定义和这个已经被static修饰后的同名的变量或者函数。

4 形参、实参、返回值

如果我们使用的函数并未进行声明,但是已经在后面进行了定义,此时会默认函数返回类型为int型,这会造成极其严重的后果。

使用的函数如果在使用之前并未定义或者可能在其他的文件中,那么就要进行声明,函数声明的目的就是告知编译器函数的返回值的类型。

注意:如果一个函数没有float、short、或者char类型的参数,在函数声明中完全可以省略掉参数类型的说明(注意,函数定义中不能省略参数类型的说明)。这种做法依赖于调用者能够提供数目正确且类型恰当的实参。这里,“恰当”并不意味着“等同”:float类型的参数会自动转换为double类型,short或者char类型的参数会自动转换为int类型。

在ANSI C标准发布之前,常常会有下面的这种声明和定义函数的方式:


int isvowel();//声明函数的方式
int isvowel(c)
		char c;
{
	return c =='a' ;
}

实际上,上面这种写法与下面这种写法是等价的:


int isvowel(int i)
{
	char c;
	return c=='a';
}

上述两种方式在VS2019中都是支持的。

看下面的例子:


#include<stdio.h>
int main()
{
	int i;
	char c;
	for (i = 0; i < 5; i++)
	{
		scanf("%d", &c);
		printf("%d ", i);
	}
	printf("\n");
	return 0;
}

表面上,这个程序从标准输入设备读入5个数,在标准输出设备设备上写5个数:

0 1 2 3 4

实际上,这个程序并不一定得到上面的结果。例如,在某个编译器上,它的输出是(当然,在VS2019环境下程序会崩溃,因为非法修改了内存空间)

0 0 0 0 0 1 2 3 4

为什么呢?问题的关键在于,这里的c被声明为char类型,而不是int类型。如果程序要求scanf读入一个整数,应该传递给他一个指向整数的指针。而程序中scanf函数得到的却是一个指向字符的指针,scanf函数并不能分辨这种情况,它只是将这个指向字符的指针作为指向整数的指针而接受,并且在指针指向的位置存储一个整数。因为整数所占的存储空间要大于字符所占的存储空间,所以字符c附近的内存被覆盖。

字符c附近的内存中存储的内容是由编译器决定的,在本例中它所存放的是整数i的低端部分。因此,每次读入一个数值到c时,都会将i的低端部分覆盖为0,而i的高端部分本来就是0,相当于i每次被重新设置为0,循环将一直进行。当到达文件的结束位置后,scanf函数不再试图读入新的值到c。这时,i才可以正常的运行,最后终止循环。

5 检查外部类型

注意:保证一个特定类型的所有外部定义在每个目标模块中都有相同的类型,“相同的类型”也应该是严格意义上的相同。

例如,在一个文件中包含定义:


char filename[] = "/etc/passwd";

而在另一个文件中包含声明:


extern char *filename;

在定义时,filename是一个字符数组的名称。尽管在一个语句中引用filename的值将得到指向该数组起始元素的指针,但是filename的类型是”字符数组“,而不是字符指针。在第二个声明中,filename被确定为一个指针。这两种方式使用存储空间的方式是不同的,它们无法以一种合乎情理的方式共存。第一个例子字符数组filename的内存布局如下图所示:

image-20220304221554347

第二种方式字符指针filename的内存布局如下图所示:

image-20220304221842175

修改方法如下图所示:


char filename[] = "/etc/passwd";
extern char filename[];

也可以这样进行修改:


char*filename = "/etc/passwd";
extern char *filename;

6 头文件

注意:每个外部对象只在一个地方声明,这个声明的地方一般就在头文件种,需要用到该外部对象的所有模块也应该 包括在这个头文件。特别指出的是,定义该外部对象的模块也应该包括这个头文件。

到此这篇关于C语言 超详细讲解链接器的文章就介绍到这了,更多相关C语言 链接器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言 超详细讲解链接器

本文链接: https://www.lsjlt.com/news/143945.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言 超详细讲解链接器
    目录1 什么是链接器2 声明与定义3 命名冲突3.1 命名冲突3.2 static修饰符4 形参、实参、返回值5 检查外部类型6 头文件1 什么是链接器 典型的链接器把由编译器或汇编...
    99+
    2022-11-13
  • C语言超详细i讲解双向链表
    目录一、双向链表的概念二、双向链表的实现三、链表与顺序表的差别四、链表oj总结一、双向链表的概念 1、概念:概念:双向链表是每个结点除后继指针外还有⼀个前驱指针。双向链表也有带头结点...
    99+
    2022-11-13
  • C语言超详细讲解线性表
    目录1. 顺序表1.1 管理结点1.2 顺序表的插入1.3 顺序表的删除1.4 顺序表的扩容2. 链表2.1 定义2.2 头部插入2.3 尾部插入2.4 任意位置插入2.5 任意位置...
    99+
    2022-11-13
  • C语言超详细讲解库函数
    目录1 返回整数的getchar函数2 更新顺序文件3 缓冲输出与内存分配4 库函数练习1 返回整数的getchar函数 代码: #include<stdio.h> ...
    99+
    2022-11-13
  • C语言数组超详细讲解上
    目录前言1、一维数组的创建和初始化1.1 一维数组的创建1.2 一维数组的初始化1.3 一维数组的使用1.4 一维数组在内存中的存储2、二维数组的创建和初始化2.1 二维数组的创建2...
    99+
    2022-11-13
  • C语言结构体超详细讲解
    目录前言1、结构体的声明1.1 结构的基础知识1.2 结构的声明1.3 结构成员的类型1.4 结构体变量的定义和初始化2、结构体成员的访问2.1 点操作符访问2.2 ->操作符...
    99+
    2022-11-13
  • C语言超详细讲解双向带头循环链表
    目录一、双向带头循环链表的结构二、双向带头循环链表的函数接口1. 申请结点2. 初识化3. 打印4. 尾插尾删5. 头插头删6. 查找7. 中间插入和删除8. 判空及求链表长度9. ...
    99+
    2023-02-14
    C语言双向带头循环链表 C语言带头循环链表 C语言循环链表
  • C语言数据结构超详细讲解单向链表
    目录1.链表概况1.1 链表的概念及结构1.2 链表的分类2. 单向链表的实现2.1 SList.h(头文件的汇总,函数的声明)2.2 SList.c(函数的具体实现逻辑)2.2.1...
    99+
    2022-11-13
  • C语言 struct结构体超详细讲解
    目录一、本章重点二、创建结构体三、typedef与结构体的渊源四、匿名结构体五、结构体大小六、结构体指针七、其他一、本章重点 创建结构体typedef与结构体的渊源匿名结构体结构体大...
    99+
    2022-11-13
  • C语言超详细讲解轮转数组
    目录题目描述实例解题思路1. 先整体逆转2.逆转子数组[0, k - 1]3.逆转子数组[k, numsSize - 1]易错点代码题目描述 给你一个数组,将数组中的元素向右轮转 k...
    99+
    2022-11-13
  • C语言函数超详细讲解上篇
    目录前言1、函数是什么?2、C语言中函数的分类2.1 库函数2.1.1 如何学会使用库函数2.1.2 自定义函数3、函数的参数3.1 实际参数(实参)3.2 形式参数(形参)4、函数...
    99+
    2022-11-13
  • C语言函数超详细讲解下篇
    目录前言函数的声明和定义函数声明函数定义举例简单的求和函数把加法单独改写成函数添加函数声明带头文件和函数声明静态库(.lib)的生成静态库文件的使用方法函数递归什么是递归?递归的两个...
    99+
    2022-11-13
  • C语言指针超详细讲解上篇
    目录前言1、指针是什么1.1 指针变量1.2 指针是内存中一个最小单元的编号2、指针和指针类型2.1 指针±类型2.2 指针的解引用2.2.1 int* 类型的解引用2...
    99+
    2022-11-13
  • C语言指针超详细讲解下篇
    目录前言指针运算指针±整数指针-指针指针的关系运算指针和数组二级指针指针数组举例 1举例 2总结前言 本文接着上一篇内容,继续学习指针相关知识点。 指针运算 指针&pl...
    99+
    2022-11-13
  • C语言超详细讲解字符串相乘
    目录前言一、分析思路二、使用步骤1、代码如下2、memset函数三、总结前言 我们已经知道,正常的两位整形数据通过*相乘,C语言中int为4字节,32bit(字节),其机器码第一位为...
    99+
    2022-11-13
  • C语言超详细讲解指针的使用
    目录指针概述自身类型指向类型代码例子数值型指针字符型指针单字符字符数组字符串型指针字符数组总结指针概述 C语言中指针也可以认为是一种类型,不同于数值型和字符型的类型。推演过去指针变量...
    99+
    2022-11-13
  • C语言操作符超详细讲解下篇
    目录前言赋值操作符单目操作符单目操作符介绍sizeof 和 数组关系操作符逻辑操作符条件操作符逗号表达式下标引用与函数调用和结构成员[ ] 下标引用操作符( ) 函数调用操作符访问一...
    99+
    2022-11-13
  • C语言操作符超详细讲解上篇
    目录前言1、操作符的分类2、算术操作符3、移位操作符3.1 左移操作符3.1.1 正数左移1位3.1.2 负数左移1位3.2 右移操作符3.2.1 正数右移1位3.2.2 负数右移1...
    99+
    2022-11-13
  • C语言哈希表概念超详细讲解
    目录1. 哈希概念2. 哈希冲突3. 哈希实现3.1 闭散列(哈希表)3.1.1 闭散列的细节3.1.2 优化后的闭散列3.2 扩散列(哈希桶)3.2.1 扩散列的细节4. 哈希表和...
    99+
    2023-02-09
    C语言哈希表 C语言哈希概念 C语言哈希实现
  • C语言超详细讲解文件的操作
    目录一、为什么使用文件二、什么是文件1.程序文件2.数据文件3.文件名三、文件指针四、文件的打开和关闭五、文件的顺序读写六、文件的随机读写fseekftellrewind七、文件结束...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作