C++中extern "C"的用法

学习过C++的人都知道,extern关键字可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。这里起到的是声明作用范围的用处。另外,extern还可以与”C”连用,作为链接指示。本文就此进行实例说明如下:

一、C++名字修饰(Name Mangling)

首先需要从C++的重载说起,在C++中函数重载指的是几个函数的函数名相同,参数列表不同。那么当生成obj中间文件/目标文件的时候,C++编译器如何区分这几个重载函数呢?可以通过把原函数名与参数信息结合,产生一个独特的内部名字,这种技术叫做名字修饰(Name Mangling)。名字修饰规则没有一个标准,所以不同的编译器的名字修饰规则也不一样。

下面是一组函数,其中f()函数重载了:

int f (void) { return 1; }
int f (int) { return 0; }
void g (void) { int i = f(), j = f(0); }

f(void)和f(int)是不同的函数,除了函数名相同以外没有任何关系。当生成obj目标文件时,为了区分它们,C++编译器根据参数信息进行了名字修饰:

int __f_v (void) { return 1; }
int __f_i (int) { return 0; }
void __g_v (void) { int i = __f_v(), j = __f_i(0); }

注意g()也被名字修饰了,虽然没有任何名字冲突。名字修饰应用于C++的任何符号。

二、为什么要使用extern “C”?

C语言中没有名字修饰(Name Mangling),因为C语言不支持函数重载。但是如果C++中含有C代码,在编译时C++编译器对C代码的函数也会进行名字修饰,函数名变了以后,将导致在C运行库中找不到对应函数,发生链接错误。

// 将下面的代码保存为.cpp文件,并用C++编译器编译
int printf(const char *format,...); 

int main()
{
  printf("GeeksforGeeks");
  return 0;
}

输出:

/tmp/ccQBO9Im.o:在函数‘main'中:
test.cpp:(.text+0xf):对‘printf(char const*, ...)'未定义的引用
collect2: 错误:ld 返回 1

为了防止C++编译器对C代码进行名字修饰,我们将C代码用extern “C”进行链接指定,告诉编译器,在生成中间文件时,不要对这部分代码进行名字修饰,而是生成符合C规则的中间符号名。

extern "C"
{
  int printf(const char *format,...);
} 

int main()
{
  printf("Hello!");
  return 0;
}

添加了extern “C”链接指示后,上面的代码就能够正常运行了。

附:所有的C风格的头文件(stdio.h, string.h, … 等等)都有在extern “C”下声明,形式如下:

#ifdef __cplusplus
extern "C" {
#endif
  /* Declarations of this file */
#ifdef __cplusplus
}
#endif
(0)

相关推荐

  • 浅谈C/C++中的static与extern关键字的使用详解

    一.C语言中的static关键字在C语言中,static可以用来修饰局部变量,全局变量以及函数.在不同的情况下static的作用不尽相同.(1)修饰局部变量一般情况下,对于局部变量是存放在栈区的,并且局部变量的生命周期在该语句块执行结束时便结束了.但是如果用static进行修饰的话,该变量便存放在静态数据区,其生命周期一直持续到整个程序执行结束.但是在这里要注意的是,虽然用static对局部变量进行修饰过后,其生命周期以及存储空间发生了变化,但是其作用域并没有改变,其仍然是一个局部变量,作用域仅

  • C/C++混合编程之extern “C”的使用示例

    前言 本文主要给大家介绍了关于C/C++混合编程extern "C"使用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 首先要明白: C++号称是C语言的超集,也确实,从语言的基本语法上,C++是包含所有C语言的语法的,而且C++为了兼容C,连C语言的标准库也被纳入到C++的标准库中,比如在C++中我们仍然可以使用<stdio.h> ,它就是C++标准库的一部分(注意最好用新的标准<cstdio> ,而不是老的<stdio&g

  • C/C++中extern "C" 的作用分析

    我们经常会在C/C++程序中见到extern "C",这是一个很重要的概念.本文就来以实例形式讲述C/C++中extern "C"的作用.分享给大家供大家参考之用.具体分析如下: 作用:实现C和C++混合编程. 原理:C和C++编译器编译之后,函数名会编译成不同的名字,链接阶段名字查找会找不到目标,后面实例中会详解. 用法: ①.c文件中定义的函数,.cpp文件要调用时,该.cpp文件中要用extern "C"声明该函数: ②.反过来,.cpp文

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

    简单来说,extern "C"是C++声明或定义C语言符号的方法,是为了与C兼容.说来容易,要理解起来还是得费些周折,首先我们要从C++和C的区别说起. 符号 大家都知道,从代码到可执行程序需要经过编译和链接两个过程,其中编译阶段会做语法检测,代码展开,另外它还会做一件事,就是将变量转成符号,链接的时候其实是通过符号来定位的.编译器在编译C和C++代码时,将变量转成符号的过程是不同的.本文所使用的编译器为gcc4.4.7 我们先来看一段简单的代码 复制代码 代码如下: /* hello

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

    C/C++ 中extern关键字详解 在C/C++编程过程中,经常会进行变量和函数的声明和定义,各个模块间共用同一个全局变量时,此时extern就派上用场了. 定义 extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义,不需要分配内存,直接使用. 推荐:在.h中声明,因为在头文件定义的话,其他模块include此头文件,就会报重复定义错误 实验结论 1.在.h中声明 extern int g_a; 在.c中定义 int g_

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

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern有两个作用,第一个,当它与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非,可能是f

  • 从汇编看c++中extern关键字的使用

    在c++中,extern关键字用来声明变量和函数,在声明函数的时候,有和没有extern的效果一样,即下面两条语句具有同样的效果: 复制代码 代码如下: extern void fun(); void fun(); 但是对于变量,有和没有extern就有区别,当有extern时,只是告知编译器存在这个变量,编译器并不为该变量分配存储空间,即真正的声明:若没有extern,则在声明的同时,编译器也为该变量分配存储空间. 下面是有extern的情形时的c++源码: 复制代码 代码如下: int ma

  • 深入理解C语言 static、extern与指针函数

    1.exit(0)正常退出程序 exit(1)程序异常时退出程序 2.static(静态变量)修饰局部变量 在局部变量使用static修饰,会延长局部变量的存在期.但我们需要注意一下几点: •虽然static修饰变量的生存期很长,但它始终是局部变量,不能在其他函数中使用•static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?     全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量.全局变量本身

  • C++中的extern声明变量详解

    extern声明变量无外乎如下两种: 1.声明全局变量 2.声明函数 今天我们只谈extern,什么const.static之类等等与之相关或不相关的一律忽略,下面就分别对以上两种情况一一讲解 声明和定义 既然提到extern声明变量,那我们就必须搞清楚声明和定义的区别. 这里我们将普通数据变量和函数统称变量.从内存分配角度来说,声明和定义的区别在于声明一个变量不会分配内存,而定义一个变量会分配内存.一个变量可以被声明多次,但是只能被定义一次. 基于以上前提,我们可以把声明和定义类比为指针和内存

  • C++中extern "C"的用法

    学习过C++的人都知道,extern关键字可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.这里起到的是声明作用范围的用处.另外,extern还可以与"C"连用,作为链接指示.本文就此进行实例说明如下: 一.C++名字修饰(Name Mangling) 首先需要从C++的重载说起,在C++中函数重载指的是几个函数的函数名相同,参数列表不同.那么当生成obj中间文件/目标文件的时候,C++编译器如何区分这几个重载函数呢?可以

  • C++中extern "C"的用法

    学习过C++的人都知道,extern关键字可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.这里起到的是声明作用范围的用处.另外,extern还可以与"C"连用,作为链接指示.本文就此进行实例说明如下: 一.C++名字修饰(Name Mangling) 首先需要从C++的重载说起,在C++中函数重载指的是几个函数的函数名相同,参数列表不同.那么当生成obj中间文件/目标文件的时候,C++编译器如何区分这几个重载函数呢?可以

  • C/C++中extern函数使用详解

    目录 一.定义和声明的区别 二.extern用法 2.1 extern 函数 2.2 extern 变量 2.3 在C++文件中调用C方式编译的函数 三.通俗讲解extern 一.定义和声明的区别 声明用来告诉编译器变量的名称和类型,而不分配内存,不赋初值. 定义为了给变量分配内存,可以为变量赋初值. 注:定义要为变量分配内存空间:而声明不需要为变量分配内存空间. 二.extern用法 2.1 extern 函数 为什么要用extern 函数呢?直接#include相应的头文件不可以嘛? 例子,

  • Oracle中游标Cursor基本用法详解

    查询 SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的 返回值被赋予INTO子句中的变量,变量的声明是在DELCARE中.SELECT INTO语法如下: SELECT [DISTICT|ALL]{*|column[,column,...]} INTO (variable[,variable,...] |record) FROM {table|(sub-query)}[alias] WHERE............ PL/SQL

  • jQuery中过滤器的基本用法示例

    本文实例讲述了jQuery中过滤器的基本用法.分享给大家供大家参考,具体如下: HTML正文: <input type="button" id="b1" value="偶数行红色"><br> <input type="button" id="b2" value="奇数行绿色"><br> <table border=1 width=&q

  • jQuery中extend函数简单用法示例

    本文实例讲述了jQuery中extend函数简单用法.分享给大家供大家参考,具体如下: var result=$.extend({},item,item1); extend给对象添加新的属性:js插件经常使用来配置参数 {}:item和item1合并后的结果 item:默认属性 item1:新增属性,如果item1和item属性重合则会覆盖item1中的属性 <span id="Test"></span> var item={"name":&

  • AngularJS中的DOM操作用法分析

    本文实例讲述了AngularJS中的DOM操作用法.分享给大家供大家参考,具体如下: 在angular中使用第三方插件时最好都封装到指令(directives)中去,DOM操作也最好都解构到指令中. 避免使用 jQuery 来操作 DOM,包括增加元素节点,移除元素节点,获取元素内容,隐藏或显示元素.你应该使用 directives 来实现这些动作,有必要的话你还要编写自己的 directives. 如果你感到很难改变习惯,那么考虑从你的网页中移除 jQuery 吧.真的,AngularJS 中

  • AngularJS中一般函数参数传递用法分析

    本文实例讲述了AngularJS中一般函数参数传递用法.分享给大家供大家参考,具体如下: 1. 模型参数 直接使用变量名,不要加引号 <!doctype html> <html ng-app="passAter"> <head> <meta charset="utf-8"/> </head> <body> <div ng-controller="passCtrl">

  • ASP.NET中Global和URLReWrite用法

    本文实例讲述了ASP.NET中Global和URLReWrite用法.分享给大家供大家参考.具体如下: Global.asax: 有时候叫做 ASP.NET 应用程序文件,提供了一种在一个中心位置响应应用程序级或模块级事件的方法.你可以使用这个文件实现应用程序安全性以及其它一些任务. 重点了解:application_Start; application_BeginRequest; application_Error; ① application_Start:自从服务器启动起来,网站第一次被访问

随机推荐