-
Notifications
You must be signed in to change notification settings - Fork 0
/
extern “C”用法详解.html
279 lines (261 loc) · 18.9 KB
/
extern “C”用法详解.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="littlewhite" />
<meta name="copyright" content="littlewhite" />
<meta property="og:type" content="article" />
<meta name="twitter:card" content="summary">
<meta name="keywords" content="c++, Language, " />
<meta property="og:title" content="extern “C”用法详解 "/>
<meta property="og:url" content="https://chukeer.github.io/extern “C”用法详解.html" />
<meta property="og:description" content="今天是接着昨天谈extern的用法,纯技术贴。目前用户数以每天1-2的数量在增长,突破100不知何时到头啊,不过昨天的文章阅读数竟然超过了用户数,看来宣传宣传还是有用的,而且看到有更多人阅读,也给了我更大写作的动力,于是我决定不定期的在这里发放小米F码!周围有朋友有需求的赶紧号召过来关注哇,不过数量有限,每次发放一个,我会提前一天预告,第二天文章推送时将F码奉上,如果你看到F码并且也需要,请赶紧使用,不然有可能被别人抢走的哦^_^ ,明天要发放的F码是米4联通3G版 简单来说,extern “C”是C++声明或定义C语言符号的方法,是为了与C兼容。说来容易,要理解起来还是得费些周折,首先我们要从C++和C的区别说起。 符号¶ 大家都知道,从代码到可执行程序需要经过编译和链接两个过程,其中编译阶段会做语法检测,代码展开,另外它还会做一件事,就是将变量转成符号,链接的时候其实是通过符号来定位的。编译器在编译C和C++代码时,将变量转成符号的过程是不同的。本文所使用的编译器为gcc4.4.7 我们先来看一段简单的代码 /* hello.c */ #include <stdio.h ..." />
<meta property="og:site_name" content="楚客" />
<meta property="og:article:author" content="littlewhite" />
<meta property="og:article:published_time" content="2014-09-29T00:00:00+08:00" />
<meta property="" content="2014-09-29T00:00:00+08:00" />
<meta name="twitter:title" content="extern “C”用法详解 ">
<meta name="twitter:description" content="今天是接着昨天谈extern的用法,纯技术贴。目前用户数以每天1-2的数量在增长,突破100不知何时到头啊,不过昨天的文章阅读数竟然超过了用户数,看来宣传宣传还是有用的,而且看到有更多人阅读,也给了我更大写作的动力,于是我决定不定期的在这里发放小米F码!周围有朋友有需求的赶紧号召过来关注哇,不过数量有限,每次发放一个,我会提前一天预告,第二天文章推送时将F码奉上,如果你看到F码并且也需要,请赶紧使用,不然有可能被别人抢走的哦^_^ ,明天要发放的F码是米4联通3G版 简单来说,extern “C”是C++声明或定义C语言符号的方法,是为了与C兼容。说来容易,要理解起来还是得费些周折,首先我们要从C++和C的区别说起。 符号¶ 大家都知道,从代码到可执行程序需要经过编译和链接两个过程,其中编译阶段会做语法检测,代码展开,另外它还会做一件事,就是将变量转成符号,链接的时候其实是通过符号来定位的。编译器在编译C和C++代码时,将变量转成符号的过程是不同的。本文所使用的编译器为gcc4.4.7 我们先来看一段简单的代码 /* hello.c */ #include <stdio.h ...">
<title>extern “C”用法详解 · 楚客
</title>
<!--
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.1/css/font-awesome.css" rel="stylesheet">
--!>
<link href="https://chukeer.github.io/theme/css/bootstrap-combined.min.css" rel="stylesheet">
<link href="https://chukeer.github.io/theme/css/font-awesome.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="https://chukeer.github.io/theme/css/pygments.css" media="screen">
<link rel="stylesheet" type="text/css" href="https://chukeer.github.io/theme/tipuesearch/tipuesearch.css" media="screen">
<link rel="stylesheet" type="text/css" href="https://chukeer.github.io/theme/css/elegant.css" media="screen">
<link rel="stylesheet" type="text/css" href="https://chukeer.github.io/theme/css/custom.css" media="screen">
</head>
<body>
<div id="content-sans-footer">
<div class="navbar navbar-static-top">
<div class="navbar-inner">
<div class="container-fluid">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="https://chukeer.github.io/"><span class=site-name>楚客</span></a>
<div class="nav-collapse collapse">
<ul class="nav pull-right top-menu">
<li ><a href="https://chukeer.github.io">Home</a></li>
<li ><a href="https://chukeer.github.io/categories.html">Categories</a></li>
<li ><a href="https://chukeer.github.io/tags.html">Tags</a></li>
<li ><a href="https://chukeer.github.io/archives.html">Archives</a></li>
<li><form class="navbar-search" action="https://chukeer.github.io/search.html" onsubmit="return validateForm(this.elements['q'].value);"> <input type="text" class="search-query" placeholder="Search" name="q" id="tipue_search_input"></form></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span1"></div>
<div class="span10">
<article>
<div class="row-fluid">
<header class="page-header span10 offset2">
<h1><a href="https://chukeer.github.io/extern “C”用法详解.html"> extern “C”用法详解 </a></h1>
</header>
</div>
<div class="row-fluid">
<div class="span2 table-of-content">
<nav>
<h4>Contents</h4>
<div class="toc">
<ul>
<li><a href="#_1">符号</a></li>
<li><a href="#extern-c">extern "C"</a></li>
</ul>
</div>
</nav>
</div>
<div class="span8 article-content">
<p>今天是接着昨天谈extern的用法,纯技术贴。目前用户数以每天1-2的数量在增长,突破100不知何时到头啊,不过昨天的文章阅读数竟然超过了用户数,看来宣传宣传还是有用的,而且看到有更多人阅读,也给了我更大写作的动力,于是我决定不定期的在这里发放小米F码!周围有朋友有需求的赶紧号召过来关注哇,不过数量有限,每次发放一个,我会提前一天预告,第二天文章推送时将F码奉上,如果你看到F码并且也需要,请赶紧使用,不然有可能被别人抢走的哦^_^ ,明天要发放的F码是<font color="red"><strong>米4联通3G版</strong></font>
<hr/></p>
<p>简单来说,extern “C”是C++声明或定义C语言符号的方法,是为了与C兼容。说来容易,要理解起来还是得费些周折,首先我们要从C++和C的区别说起。</p>
<h2 id="_1">符号<a class="headerlink" href="#_1" title="Permanent link">¶</a></h2>
<p>大家都知道,从代码到可执行程序需要经过编译和链接两个过程,其中编译阶段会做语法检测,代码展开,另外它还会做一件事,就是将变量转成符号,链接的时候其实是通过符号来定位的。编译器在编译C和C++代码时,将变量转成符号的过程是不同的。本文所使用的编译器为gcc4.4.7</p>
<p>我们先来看一段简单的代码</p>
<div class="highlight"><pre><span></span><span class="cm">/* hello.c */</span>
<span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">g_prefix</span> <span class="o">=</span> <span class="s">"hello "</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">hello</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">name</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"%s%s"</span><span class="p">,</span> <span class="n">g_prefix</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<p>注意,这里的文件名为hello.c,我们执行编译<code>gcc -c hello.c</code>得到目标文件hello.o,在Linux下用nm查看目标文件的符号表得到如下结果(<code>$</code>符号代表shell命令提示符)</p>
<div class="highlight"><pre><span></span>$ nm hello.o
<span class="m">0000000000000000</span> D g_prefix
<span class="m">0000000000000000</span> T hello
U <span class="nb">printf</span>
</pre></div>
<p>这是C代码编译后的符号列表,其中第三列为编译后的符号名,我们主要看自己定义的全局变量g_prefix和函数hello,它们的编译后的符号名和代码里的名字是一样的。我们将hello.c重命名为hello.cpp,重新编译<code>gcc -c hello.cpp</code>得到hello.o,在用nm查看,结果如下</p>
<div class="highlight"><pre><span></span>0000000000000000 T _Z5helloPKc
U __gxx_personality_v0
0000000000000000 D g_prefix
U printf
</pre></div>
<p>这是C++代码编译后的符号列表,gcc会自动根据文件后缀名来识别C和C++代码,这时我们发现g_prefix的符号没变,但函数hello的符号变成了<code>_Z5helloPKc</code>,这就说明gcc在编译C和C++代码时处理方式是不一样的,对于C代码,变量的符号名就是变量本身(在早期编译器会为C代码变量前加下划线<code>_</code>,现在默认都不会了,在编译时可以通过编译选项<code>-fno-leading-underscore</code>和<code>-fleading-underscore</code>来显式设置),而对于C++代码,如果是数据变量并且没有嵌套,符号名也是本身,如果变量名有嵌套(在名称空间或类里)或者是函数名,符号名就会按如下规则来处理</p>
<p>1、 符号以<code>_Z</code>开始<br/>
2、 如果有嵌套,后面紧跟<code>N</code>,然后是名称空间、类、函数的名字,名字前的数字是长度,以<code>E</code>结尾<br/>
3、 如果没嵌套,则直接是名字长度后面跟着名字<br/>
4、 最后是参数列表,类型和符号对应关系如下 </p>
<div class="highlight"><pre><span></span> int -> i
float -> f
double -> d
char -> c
void -> v
const -> K
* -> P
</pre></div>
<p>这样就很好理解为什么C++代码里的void hello(const char*)编译之后符号为_Z5helloPKc(PKc翻译成类型要从右到左翻译为<code>char const *</code>,这是编译器内部的表示方式,我们习惯的表示方式是<code>const char*</code>,两者是一样的),<code>c++filt</code>工具可以从符号反推名字,使用方法为<code>c++filt _Z5helloPKc</code></p>
<p>下面列举几个函数和符号的对应例子</p>
<table>
<thead>
<tr>
<th align="center">函数和变量</th>
<th align="right">符号</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">int func(int, int)</td>
<td align="right">_Z4funcii</td>
</tr>
<tr>
<td align="center">float func(float)</td>
<td align="right">_Z4funcf</td>
</tr>
<tr>
<td align="center">int C::func(int)</td>
<td align="right">_ZN1C4funcEi</td>
</tr>
<tr>
<td align="center">int C::C2::func(int)</td>
<td align="right">_ZN1C2C24funcEi</td>
</tr>
<tr>
<td align="center">int C::var</td>
<td align="right">_Z1C3varE</td>
</tr>
</tbody>
</table>
<p>这样也很容易理解为什么C++支持函数重载而C不支持了,因为C++将函数修饰为符号时把函数的参数类型加进去了,而C却没有,所以在C++下,即便函数名相同,只要参数不同,它们的符号名是不会冲突的。我们可以通过下面一个例子来验证变量名和符号的这种关系</p>
<div class="highlight"><pre><span></span><span class="o">/</span> <span class="o">*</span> <span class="nl">filename</span> <span class="p">:</span> <span class="n">test</span><span class="p">.</span><span class="n">cpp</span> <span class="err">*/</span>
<span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="n">namespace</span> <span class="n">myname</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">var</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">extern</span> <span class="kt">int</span> <span class="n">_ZN6myname3varE</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">_ZN6myname3varE</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>这里我们在名称空间namespace定义了全局变量var,根据前面的内容,它会被修饰为符号<code>_ZN6myname3varE</code>,然后我们手动声明了外部变量<code>_ZN6myname3varE</code>并将其打印出来。编译并运行,它的值正好就是var的值</p>
<div class="highlight"><pre><span></span>$ gcc test.cpp -o <span class="nb">test</span> -lstdc++
$ ./test
42
</pre></div>
<h2 id="extern-c">extern "C"<a class="headerlink" href="#extern-c" title="Permanent link">¶</a></h2>
<p>有了符号的概念我们再来看extern “C”的用法就很容易了</p>
<div class="highlight"><pre><span></span>extern "C"
{
int func(int);
int var;
}
</pre></div>
<p>它的意思就是告诉编译器将extern “C”后面的括号里的代码当做C代码来处理,当然我们也可以以单条语句来声明</p>
<div class="highlight"><pre><span></span>extern "C" int func(int);
extern "C" int var;
</pre></div>
<p>这样就声明了C类型的func和var。很多时候我们写一个头文件声明了一些C语言的函数,而这些函数可能被C和C++代码调用,当我们提供给C++代码调用时,需要在头文件里加extern “C”,否则C++编译的时候会找不到符号,而给C代码调用时又不能加extern “C”,因为C是不支持这样的语法的,常见的处理方式是这样的,我们以C的库函数memset为例</p>
<div class="highlight"><pre><span></span><span class="cp">#ifdef __cplusplus</span>
<span class="k">extern</span> <span class="s">"C"</span> <span class="p">{</span>
<span class="cp">#endif</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">memset</span><span class="p">(</span><span class="kt">void</span><span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">,</span> <span class="kt">size_t</span><span class="p">);</span>
<span class="cp">#ifdef __cplusplus</span>
<span class="p">}</span>
<span class="cp">#endif</span>
</pre></div>
<p>其中<code>__cplusplus</code>是C++编译器定义的一个宏,如果这份代码和C++一起编译,那么memset会在extern "C"里被声明,如果是和C代码一起编译则直接声明,由于<code>__cplusplus</code>没有被定义,所以也不会有语法错误。这样的技巧在系统头文件里经常被用到。
<hr>
点击阅读原文查看我的博客,如果觉得本文有价值,请为我点个赞,或者为我增加一个读者</hr></p>
<hr/>
<aside>
<nav>
<ul class="articles-timeline">
<li class="previous-article">« <a href="https://chukeer.github.io/如何打造舒适的linux开发环境.html" title="Previous: 如何打造舒适的linux开发环境">如何打造舒适的linux开发环境</a></li>
<li class="next-article"><a href="https://chukeer.github.io/Mac必备软件推荐.html" title="Next: Mac必备软件推荐">Mac必备软件推荐</a> »</li>
</ul>
</nav>
</aside>
</div>
<section>
<div class="span2" style="float:right;font-size:0.9em;">
<table class="table">
<!-- <time pubdate="pubdate" datetime="2014-09-29T00:00:00+08:00"> 9 29, 2014</time> -->
<tr>
<td>Published</td>
<td><time pubdate="pubdate" datetime="2014-09-29T00:00:00+08:00">2014- 9-29</time></td>
</tr>
<tr>
<td>Category</td>
<td><a class="category-link" href="https://chukeer.github.io/categories.html#language-ref">Language</a></td>
</tr>
<tr>
<td>Tags</td>
<td>
<ul class="list-of-tags tags-in-article">
<li><a href="https://chukeer.github.io/tags.html#c-ref">c++
<span>15</span>
</a></li>
</ul>
</td>
</tr>
</table>
</div>
</section>
</div>
</article>
</div>
<div class="span1"></div>
</div>
</div>
<div id="push"></div>
</div>
<footer>
<div id="footer">
<ul class="footer-content">
<li class="elegant-power">Powered by <a href="http://getpelican.com/" title="Pelican Home Page">Pelican</a>. Theme: <a href="http://oncrashreboot.com/pelican-elegant" title="Theme Elegant Home Page">Elegant</a> by <a href="http://oncrashreboot.com" title="Talha Mansoor Home Page">Talha Mansoor</a></li>
</ul>
</div>
</footer> <!--
<script src="http://code.jquery.com/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
-->
<script src="https://chukeer.github.io/theme/js/jquery.min.js"></script>
<script src="https://chukeer.github.io/theme/js/bootstrap.min.js"></script>
<script>
function validateForm(query)
{
return (query.length > 0);
}
</script>
<script>
$("div.article-content table").addClass("table table-hover");
</script>
</body>
<!-- Theme: Elegant built for Pelican
License : http://oncrashreboot.com/pelican-elegant -->
</html>