C语言关键字学习(1)----- extern

来源:互联网 发布:2016年云计算行业分析 编辑:程序博客网 时间:2024/04/30 02:18

序言:

       如果C语言是程序员手下的一支精锐之师,那么基本语法是它的主力军,而关键字则是士兵们手中的利器。对于一个需要经常驰骋疆场的C程序员来说,如果不能把这柄利器运用自如的话,那么不仅会失去“一夫当关,万夫莫开”的雄风,甚至还会伤及自身。因此,我开了这么一个序列,尝试将兵器库里的各种奇异兵器玩耍一遍。另外,这里我介绍的关键字都是实践中遇到的。


一. 不要再见外了-----extern

(1)前几天在南理工车库调试程序的时候,在编译工程的时候,编译器爆出这么一个错误:Undefined reference to "getSockfdToServer"。很显然,这说明编译器并未找到getSockfdToServer函数的定义。起初,我以为是因为连接器没有找到定义该函数的库。于是,我仔细地检查了相关的CMakeLists.txt文件,以及是否有包含该函数声明的头文件等等,可问题依然存在。就在心灰意冷之际,事情却突然发生了转机。在查看声明该函数定义的头文件中,我发现下面这个重要的东西被人注释掉了。


#ifdef __cplusplus   extern "C" {#endif......#ifdef __cplusplus  }#endif

而定义该函数的库文件是.cpp文件。显然问题已经很清楚了,没有了上面的那段代码,编译器在编译getSockfdToServer的时候,就会按照C++的编译方式进行。而我们的工程却是用C的方式编译的,所以连接器在库里找不到该函数的定义。extern "C“ 只是extern的一种用法之一。以下引用百度百科对这一用法的详细叙述:

被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;  

未加extern “C”声明时的编译方式。  

首先看看C++中对类似C的函数是怎样编译的。作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:  

void foo( int x, int y );  该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。  同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。


(2)extern更多地是用来修饰变量。我们知道每个变量都有它的作用域,全局变量在该文件中任何地方都可引用,而局部变量则只能在一个特定的作用域内使用。有时工程中会出现这样的情况:在几个文件中可能都需要使用同一个变量。这时候extern便能满足你这种诉求。例如,我们在a.c文件中定义了变量int a,如果要在b.c文件中引用变量a,只需要在b.c文件中这样"extern int a"申明即可。当然,首先得保证变量a的链接属性是外部链接的,即变量a首先得能够在a.c文件中被引用,通常它应该是全局变量。另外,extern int a也可以写在一个函数定义的开头处,这样的话,就只能在该函数内引用该变量。


(3)extern修饰函数跟修饰变量差不多。

原创粉丝点击