最全《C陷阱与缺陷》----第四章 链接器_c语言陷阱与缺陷第四章总结,从入门到精通的C C++进阶学习笔记整理

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


出现在一个源文件中,而



int a = 9;


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


## 4.3 命名冲突


### 4.3.1 命名冲突


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



int a;


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


### 4.3.2 static修饰符



static int a;


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


## 4.4 形参、实参、返回值


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


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


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


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



int isvowel();//声明函数的方式
int isvowel©
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才可以正常的运行,最后终止循环。
> 
> 
> 


## 4.5 检查外部类型


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


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



char filename[] = “/etc/passwd”;


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



extern char *filename;



![img](https://img-blog.csdnimg.cn/img_convert/715a90c30fc1164be7d688dd03cd0963.png)
![img](https://img-blog.csdnimg.cn/img_convert/b50ed2369c7e1c2539b125ad6e5aab44.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值