`
java-mans
  • 浏览: 11421877 次
文章分类
社区版块
存档分类
最新评论

extern c详解(上)

 
阅读更多
文章修改自:<wbr style="line-height:25px"><a rel="nofollow" href="http://wenku.baidu.com/view/8872c444b307e87101f69650.html" style="color:rgb(207,121,28); line-height:25px; text-decoration:none">http://wenku.baidu.com/view/8872c444b307e87101f69650.html</a> <div style="line-height:25px"> <div style="line-height:25px"><span style="line-height:25px"><span style="font-size:16px; line-height:28px">引言</span></span></div> <div style="line-height:25px"><span style="color:#003366; line-height:25px">在用C++的项目源码中,经常会不可避免的会看到下面的代码:</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">#ifdef __cplusplus</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">extern "C" {</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">#endif</span></div> <div style="line-height:25px"><span style="line-height:25px; color:rgb(51,102,255)"><span style="line-height:25px; white-space:pre"></span>/*...*/</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">#ifdef __cplusplus</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">}</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">#endif</span></div> <div style="line-height:25px"><span style="color:#003366; line-height:25px">它到底有什么用呢,你知道吗?而且这样的问题经常会出现在面试or笔试中。下面我就从以下几个方面来介绍它:</span></div> <div style="line-height:25px"><span style="line-height:25px"><span style="font-size:16px; line-height:28px">一、#ifdef _cplusplus/#endif _cplusplus及发散</span></span></div> <div style="line-height:25px"> <span style="color:#003366; line-height:25px">在介绍extern "C"之前,我们来看下</span><span style="color:#0000ff; line-height:25px">#ifdef _cplusplus/#endif _cplusplus</span><span style="color:#003366; line-height:25px">的作用。很明显</span><span style="color:#0000ff; line-height:25px">#ifdef/#endif、#ifndef/#endif</span><span style="color:#003366; line-height:25px">用于条件编译,</span><span style="color:#0000ff; line-height:25px">#ifdef _cplusplus/#endif _cplusplus</span><span style="color:#003366; line-height:25px">——表示如果定义了宏_cplusplus,就执行#ifdef/#endif之间的语句,否则就不执行。</span> </div> <div style="line-height:25px"><span style="color:#003366; line-height:25px">在这里为什么需要#ifdef _cplusplus/#endif _cplusplus呢?因为C语言中不支持extern "C"声明,如果你明白extern "C"的作用就知道在C中也没有必要这样做,这就是条件编译的作用!在.c文件中包含了extern "C"时会出现编译时错误。</span></div> <div style="line-height:25px"><span style="color:#003366; line-height:25px">既然说到了条件编译,我就介绍它的一个重要应用——避免重复包含头文件。下面是一个开源web服务器——Mongoose的头文件mongoose.h中的一段代码:</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">#ifndef MONGOOSE_HEADER_INCLUDED</span></div> <div style="line-height:25px"> <span style="color:#0000ff; line-height:25px">#define MONGOOSE_HEADER_INCLUDED</span><span style="line-height:25px; color:rgb(51,102,255); white-space:pre"> </span><span style="color:#3366ff; line-height:25px"></span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"> #ifdef __cplusplus</span></div> <div style="line-height:25px"> <span style="line-height:25px; color:rgb(51,102,255); white-space:pre"></span><span style="color:#ff6600; line-height:25px">extern "C"</span><span style="color:#3366ff; line-height:25px">{</span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span>#endif /* __cplusplus */</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span></span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span>/*.................................</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span>* do something here</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span>*.................................</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span>*/</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span></span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span>#ifdef __cplusplus</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span>}</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span>#endif /* __cplusplus */</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">#endif /* MONGOOSE_HEADER_INCLUDED */</span></div> <div style="line-height:25px"> <span style="color:#003366; line-height:25px">这个头文件mongoose.h可能在项目中被多个源文件包含(#include "mongoose.h"),而对于一个大型项目来说,这些冗余可能导致错误,因为一个头文件包含类定义或inline函数,在一个源文件中mongoose.h可能会被#include两次(如,a.h头文件包含了mongoose.h,而在b.c文件中#include a.h和mongoose.h)——这就会出错(在同一个源文件中一个结构体、类等被定义了两次)。</span><span style="line-height:25px; color:rgb(0,51,102)">从逻辑观点和减少编译时间上,都要求去除这些冗余。然而让程序员去分析和去掉这些冗余,不仅枯燥且不太实际,最重要的是有时候又需要这种冗余来保证各个模块的独立。</span> </div> <div style="line-height:25px"><span style="color:#000080; line-height:25px">为了解决这个问题,上面代码中的</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">#ifndef MONGOOSE_HEADER_INCLUDED</span></div> <div style="line-height:25px"><span style="color:#0000ff; line-height:25px">#define MONGOOSE_HEADER_INCLUDED</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">/*……………………………*/</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px">#endif /* MONGOOSE_HEADER_INCLUDED */</span></div> <div style="line-height:25px"><span style="color:#003366; line-height:25px">就起作用了。如果定义了MONGOOSE_HEADER_INCLUDED,#ifndef/#endif之间的内容就被忽略掉。因此,编译时第一次看到mongoose.h头文件,它的内容会被读取且给定MONGOOSE_HEADER_INCLUDED一个值。之后再次看到mongoose.h头文件时,MONGOOSE_HEADER_INCLUDED就已经定义了,mongoose.h的内容就不会再次被读取了。</span></div> <div style="line-height:25px"><span style="line-height:25px"><span style="font-size:16px; line-height:28px">二、extern "C"</span></span></div> <div style="line-height:25px"><span style="color:#003366; line-height:25px">首先从字面上分析extern "C",它由两部分组成——extern关键字、"C"。下面我就从这两个方面来解读extern "C"的含义。</span></div> <div style="line-height:25px"><span style="line-height:25px">2.1、extern关键字</span></div> <div style="line-height:25px"><span style="color:#000080; line-height:25px">在一个项目中必须保证函数、变量、枚举等在所有的源文件中保持一致,除非你指定定义为局部的。首先来一个例子:</span></div> <div style="line-height:25px"> <span style="line-height:25px; white-space:pre"></span>file1.c文件</div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> int x=1;</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> int f(){do something here}</span></div> <div style="line-height:25px"> <span style="line-height:25px; white-space:pre"></span>file2.c文件</div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> extern int x;</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> int f();</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> void g(){x=f();}</span></div> <div style="line-height:25px"> <span style="color:#000080; line-height:25px">在file2.c中g()使用的x和f()是定义在file1.c中的。extern关键字表明file2.c中x,仅仅是一个变量的声明,其并不是在定义变量x,并未为x分配内存空间。变量x在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。但是可以声明多次,且声明必须保证类型一致,如</span>:</div> <div style="line-height:25px"> <span style="line-height:25px; white-space:pre"></span>file1.c文件</div> <div style="line-height:25px"> <span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span></span><span style="color:#0000ff; line-height:25px">int x=1;</span> </div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> int b=1;</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> extern c;</span></div> <div style="line-height:25px"> <span style="line-height:25px; white-space:pre"></span>file2.c文件</div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> int x;// x equals to default of int type 0</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> int f();</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> extern double b;</span></div> <div style="line-height:25px"><span style="color:#3366ff; line-height:25px"><span style="line-height:25px; white-space:pre"></span> extern int c;</span></div> <div style="line-height:25px"> <span style="color:#003366; line-height:25px">在这段代码中存在着这样的三个错误</span>:</div> <div style="line-height:25px"><span style="color:#0000ff; line-height:25px">x被定义了两次</span></div> <div style="line-height:25px"><span style="color:#0000ff; line-height:25px">b两次被声明为不同的类型</span></div> <div style="line-height:25px"><span style="color:#0000ff; line-height:25px">c被声明了两次,但却没有定义</span></div> <div style="line-height:25px"> <span style="color:#000080; line-height:25px">在C/C++语言中,</span><span style="color:#ff6600; line-height:25px">extern关键字</span><span style="color:#000080; line-height:25px">告诉编译器</span><span style="color:#ff6600; line-height:25px">在所有的模块中(不仅仅是本地模块)查找该函数和全局变量的定义。</span><span style="color:#000080; line-height:25px">通常,</span><span style="color:#ff6600; line-height:25px">在模块的头文件中,对于本模块提供给其它模块引用的函数和全局变量应以关键字extern声明</span><span style="color:#000080; line-height:25px">。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;在连接阶段,连接器会在所有模块找查找该函数的定义,这里它将在模块A中找到了该函数的定义。</span> </div> <div style="line-height:25px"><span style="color:#ff6600; line-height:25px">与extern对应的关键字是 static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。</span></div> <div style="line-height:25px"><span style="line-height:25px">2.2、"C"</span></div> <div style="line-height:25px"><span style="color:#003366; line-height:25px">一个C++程序包含其它语言编写的部分代码,同理,C++编写的代码片段可能被使用在其它语言编写的代码中。不同语言编写的代码互相调用是困难的,即使是同一种编写的代码但不同的编译器编译的代码。例如,不同语言和同种语言的不同实现可能会在注册变量保持参数和参数在栈上的布局,这个方面不一样。</span></div> <div style="line-height:25px"><span style="color:#000080; line-height:25px">为了使它们遵守统一规则,可以使用extern指定一个编译和连接规约。例如,声明C和C++标准库函数strcyp(),并指定它应该根据C的编译和连接规约来链接:</span></div> <div style="line-height:25px"> <span style="color:#ff6600; line-height:25px">extern "C"</span><span style="color:#0000ff; line-height:25px">char* strcpy(char*,const char*);</span> </div> <div style="line-height:25px"><span style="color:#000080; line-height:25px">注意它与下面的声明的不同之处:</span></div> <div style="line-height:25px"> <span style="color:#ff6600; line-height:25px">extern</span><span style="color:#0000ff; line-height:25px">char* strcpy(char*,const char*);</span> </div> <div style="line-height:25px"><span style="color:#000080; line-height:25px">下面的这个声明仅表示在连接的时候调用strcpy()。</span></div> <div style="line-height:25px"> <span style="color:#ff6600; line-height:25px">extern "C"指令中的C,表示的一种编译和连接规约,而不是一种语言。C表示符合C语言的编译和连接规约的任何语言,如Fortran、assembler等。extern "C"指令仅指定编译和连接规约,但不影响语义</span>。<span style="color:#000080; line-height:25px">例如在函数声明中,指定了extern "C",仍然要遵守C++的类型检测、参数转换规则。</span> </div> <div style="line-height:25px"><span style="color:#000080; line-height:25px">再看下面的一个例子,为了声明一个变量而不是定义一个变量,你必须在声明时指定extern关键字,但是当你又加上了"C",它不会改变语义,但是会改变它的编译和连接方式。</span></div> <div style="line-height:25px"><span style="color:#000080; line-height:25px">如果你有很多语言要加上extern "C",你可以将它们放到extern "C"{ }中。</span></div> <div style="line-height:25px"><span style="line-height:25px">2.3、小结extern "C"</span></div> <div style="line-height:25px"> <span style="color:#003366; line-height:25px">通过上面两节的分析,我们知道extern "C"的真实目的是实现类C和C++的混合编程。在C++源文件中的语句前面加上extern "C",表明它按照类C的编译和连接规约来编译和连接,而不是C++的编译的连接规约。这样在</span><span style="color:#0000ff; line-height:25px">类C</span><span style="color:#003366; line-height:25px">的代码中就可以调用C++的函数or变量等</span>。(<span style="line-height:25px">注</span>:<span style="color:#000080; line-height:25px">我在这里所说的类C,代表的是跟C语言的编译和连接方式一致的所有语言</span>)</div> </div> </wbr>
分享到:
评论

相关推荐

    C语言中extern关键字详解.docx

    C语言中extern关键字详解.docx ,C语言中extern关键字详解.docx

    关于externC的超详解

    关于extern C 的超级详解。解决以后所有包含extern C 的代码。

    C语言中extern关键字详解[参考].pdf

    C语言中extern关键字详解[参考].pdf

    extern用法详解

    extern用法详解 讲述 c\c++ extern关键字的用法…… 貌似非入门必备,但有备无患……

    extern 'C' 详解

    extern 'C' 详解

    c语言中extern关键字详解.doc

    c语言中,有众多的关键字,这里对extern关键字进行详细的阐述,希望能加深大家的理解!

    extern “C”使用详解.doc

    extern “C”使用详解,extern “C”使用详解extern “C”使用详解extern “C”使用详解

    C/C++ 中extern关键字详解

    C/C++ 中extern关键字详解 在C/C++编程过程中,经常会进行变量和函数的声明和定义,各个模块间共用同一个全局变量时,此时extern就派上用场了。 定义 extern可以置于变量或者函数前,以标示变量或者函数的定义在别的...

    C++中的extern “C”用法详解

    主要介绍了C++中的extern “C”用法详解,简单来说,extern “C”是C++声明或定义C语言符号的方法,是为了与C兼容,需要的朋友可以参考下

    探索C++的秘密之详解extern

    本文主要介绍了C+中extern的用法,希望对你的学习有所帮助。

    探索C++的秘密之详解extern C

    如果想要取得尽量好的与平台无关性,则在.h文件头加入extern "C",强制编译器以C方法编译.cpp的文件,生成的文件名不会像.cpp那样给函数加上一堆附加信息。这样其他的编译器也可能识别他。但是这种方法只适合没有...

    C/C++中extern关键字详解

     也是说extern有两个作用,第一个,当它与C一起连用时,如: extern C void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun...

    高级C语言详解

    60. 高级C语言程序员测试必过的十六道最佳题目+答案详解 297 61. C语言常见错误 320 62. 超强的指针学习笔记 325 63. 程序员之路──关于代码风格 343 64. 指针、结构体、联合体的安全规范 346 65. C指针讲解 352 66...

    实例详解C/C++中extern关键字

    主要介绍了C/C++中extern关键字详解 的相关资料,需要的朋友可以参考下

    C++调用C函数实例详解

    调用C语言的函数,需要在函数声明的地方语句extern “C”。如果不使用该语句,在链接的时候,编译器就会报以下这种错误。 Test.obj : error LNK2019: 无法解析的外部符号 “void __cdecl DeleteStack(struct _Node *...

    详解C语言正确使用extern关键字

    利用关键字extern,可以在一个文件中引用另一个文件中定义的变量或者函数,下面就结合具体的实例,分类说明一下。 一、引用同一个文件中的变量 #include int func(); int main() { func(); //1 printf(%d,num); /...

Global site tag (gtag.js) - Google Analytics