C语言编程陷阱:链接陷阱

简介: 每一个外部变量只在一个地方声明,这个声明的地方一般就在一个头文件中,需要用到该外部的所有模块都应该包括这个头文件。推荐一个零声学院免费教程,个人觉得老师讲得不错, 服务器课程

4.链接


  • 什么是连接器
  • C语言可能是由多个分别编译的部分组成,这些不同部分通过一个通常叫做连接器的程序合并成一个整体
  • 编译器一般每次只能处理一个文件,所以它不能检测出哪些需要一次了解多个源程序文件才能察觉的错误
  • 连接器能够理解机械语言和内存布局
  • 典型的连接器是把编译器或汇编器生成的若干个目标模块,整合成被称位载入模块或可执行文件的实体,该实体能够被操作系统直接执行。其中某些目标模块是直接作为输入提供给连接器的。而另外一些目标模块则是根据连接过程的需要,从包括有类型printf函数的库文件中取得的
  • 连接器通常把目标模块看成是由一组外部对象组成的。每个外部对象代表着机器内存中的某个部分,通过一个外部名称来识别。因此程序中的每个函数和每个外部变量,如果没有被声明为static就都是一个外部对象
  • 某些编译器会对静态函数和静态变量的名称做一定改变,将它们作为外部对象,因为经过了名称修饰,所以不会与其他的源程序文件中的同名函数或同名变量发生命名冲突。
  • 大多数的连接器都禁止同一个载入模块中的两个不同外部对象拥有相同名称。连接器的一个主要工作就是处理这类的命名冲突问题
  • 声明与定义
  • int a;
  • 全局声明的情况下,说明了a就是一个外部整型变量,同时为a分配存储空间,因为外部对象a并没有被明确指定任何初始值,所以他的初始值默认为0,(某些系统中连接器对以其他语言编写的程序并不保证这一点)
  • int a = 7;
  • 定义a同时也给a明确指定了初始值。
  • extren int a;
  • 这个语句并不是对a的定义,但是仍然说明了a是一个外部整型变量。显示地说明了a的存储空间是再程序的其他地方分配的。
  • 从连接器的角度来看,上述声明是对外部变量a的引用,而不是对a的定义。
  • 这种形式的声明是对一个外部对象的显示引用,即使它出现在一个函数的内部,也仍然具有相同的涵义。
  • 命名冲突与static修饰符
  • static int a;和int a ;含义相同把a的作用域限定在一个源文件内,对其他的源文件 a是不可见的
  • 如果若干个函数需要共享一组外部对象,可以将这些函数放到一个源文件中,把它们需要用到的对象,也都在同—个源文件中以static修饰符声明
  • 形参、实参与返回值
  • 任何的C函数都有一个函数列表,列表中的每个参数都是一个变量。改变量在函数调用过程中被初始化
  • 形参列表允许为空
  • 函数调用时,调用方将实参列表传递给被调函数
  • 任何一个C函数都有一个返回类型,要不就是void要么是函数生成的结果类型
  • 依赖于调用者能够提供数目正确且类型恰当的实参查外部类型
  • 保证一个特定名称的所有外部定义在每个目标模块中都有相同的类型应该是严格意义上的相同
  • 头文件
  • 每一个外部变量只在一个地方声明,这个声明的地方一般就在一个头文件中,需要用到该外部的所有模块都应该包括这个头文件。
  • 推荐一个零声学院免费教程,个人觉得老师讲得不错, 服务器课程
目录
相关文章
|
1月前
|
存储 自然语言处理 编译器
【C语言】编译与链接:深入理解程序构建过程
【C语言】编译与链接:深入理解程序构建过程
|
1月前
|
自然语言处理 编译器 Linux
【C语言篇】编译和链接以及预处理介绍(上篇)1
【C语言篇】编译和链接以及预处理介绍(上篇)
40 1
|
1月前
|
存储 自然语言处理 编译器
|
1月前
|
编译器 Linux C语言
【C语言篇】编译和链接以及预处理介绍(下篇)
【C语言篇】编译和链接以及预处理介绍(下篇)
32 1
【C语言篇】编译和链接以及预处理介绍(下篇)
|
1月前
|
NoSQL C语言 索引
十二个C语言新手编程时常犯的错误及解决方式
C语言初学者常遇错误包括语法错误、未初始化变量、数组越界、指针错误、函数声明与定义不匹配、忘记包含头文件、格式化字符串错误、忘记返回值、内存泄漏、逻辑错误、字符串未正确终止及递归无退出条件。解决方法涉及仔细检查代码、初始化变量、确保索引有效、正确使用指针与格式化字符串、包含必要头文件、使用调试工具跟踪逻辑、避免内存泄漏及确保递归有基准情况。利用调试器、编写注释及查阅资料也有助于提高编程效率。避免这些错误可使代码更稳定、高效。
220 12
|
1月前
|
自然语言处理 编译器 Linux
C语言中抽象的编译和链接原理
C语言中抽象的编译和链接原理
20 1
|
2月前
|
存储 算法 Linux
C语言 多进程编程(一)进程创建
本文详细介绍了Linux系统中的进程管理。首先,文章解释了进程的概念及其特点,强调了进程作为操作系统中独立可调度实体的重要性。文章还深入讲解了Linux下的进程管理,包括如何获取进程ID、进程地址空间、虚拟地址与物理地址的区别,以及进程状态管理和优先级设置等内容。此外,还介绍了常用进程管理命令如`ps`、`top`、`pstree`和`kill`的使用方法。最后,文章讨论了进程的创建、退出和等待机制,并展示了如何通过`fork()`、`exec`家族函数以及`wait()`和`waitpid()`函数来管理和控制进程。此外,还介绍了守护进程的创建方法。
C语言 多进程编程(一)进程创建
|
1月前
|
存储 C语言
【C语言篇】编译和链接以及预处理介绍(上篇)2
【C语言篇】编译和链接以及预处理介绍(上篇)
36 0
|
2月前
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。
|
2月前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。