唐山古冶网上找学生妹子上门博天堂手机app的联系方式服务【选妹微,信:29553458】(美女)(服务)(上门)
(原标题:东莞家具摄影设计乐艺摄影设计)
唐山古冶大学校区小妹【选妹微,信:29553458】(美女)(服务)(上门) 唐山古冶约学院妹【选妹微,信:685495o7】(美女)(服务)(上门) 唐山古冶找外围女上门一条龙【选妹微,信:685495o7】(美女)(服务)(上门) 唐山古冶哪里有站鸡街【选妹微,信:44716721】(美女)(服务)(上门) 唐山古冶海口海经院的鸡怎么找【选妹微,信:4344o362o】(美女)(服务)(上门) 唐山古冶后街晚上几点有女人【选妹微,信:44716721】(美女)(服务)(上门) 唐山古冶学院学生提供服务【选妹微,信:29553458】(美女)(服务)(上门) 唐山古冶娄底卫校暗语【选妹微,信:4344o362o】(美女)(服务)(上门) 唐山古冶江宁大学城炮群【选妹微,信:44716721】(美女)(服务)(上门) 唐山古冶2019红灯一条街在哪【选妹微,信:4344o362o】(美女)(服务)(上门) 唐山古冶2019东莞长安沐足最爽【选妹微,信:29553458】(美女)(服务)(上门)c 中extern “c”含义深层探索
1.引言
c 语言的1kz7创建初衷是“a better c”,〖但〗〖是〗〖这〗〖并〗〖不〗〖意〗〖味〗〖着〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖c〗〖 〗〖 〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖中〗〖类〗〖似〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖c〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖语〗〖言〗〖的〗〖1〗〖k〗〖〗〖〗〖〗〖〗〖z〗〖7〗〖全〗〖局〗〖变〗〖量〗〖d〗〖2〗〖〗〖〗〖〗〖〗〖〗〖8〗〖z〗〖和〗〖函〗〖数〗〖所〗〖采〗〖用〗〖的〗〖编〗〖译〗〖和〗〖连〗〖接〗〖方〗〖式〗〖与〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖c〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖语〗〖言〗〖完〗〖全〗〖相〗〖同〗〖。〗〖作〗〖为〗〖一〗〖4〗〖v〗〖〗〖〗〖〗〖〗〖〗〖1〗〖2〗〖9〗〖5〗〖〗〖〗〖〗〖〗〖〗〖2〗〖p〗〖种〗〖欲〗〖与〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖c〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖兼〗〖容〗〖的〗〖语〗〖言〗,c 保留了一部分过程式语言的1kz7特点(被世人称为“不彻底nm3s地面向对象”),因而它可以定5235义不属于任何类的全局变量d28z和函数。但是,c 毕竟是一种面9l5u向对象的程序设计语言,为了支持函数的重载,c 对全局函数的处理方式与c有明显3b5q的不同。
2.从标准头文件说起
某企业曾经给出如下的一道面试题v494:
面试题v494
为什么标准头文件都ozto有类似以下的结构?
#ifndef
__incvxworksh
#define __incvxworksh
#ifdef __cplusplus
extern "c" {
#endif
#ifdef __cplusplus
}
#endif
#endif
分析
显然,头文件中的编译宏“#ifndef
__incvxworksh、#define
__incvxworksh、#endif” 的作用是防止该头文c508件被重复引用。
那么
#ifdef __cplusplus
extern "c" {
#endif
#ifdef __cplusplus
}
#endif
的作用又是什么呢?我们将在下文一一道来。
3.深层揭u142密extern "c"
extern "c" 包含双重含义,从字面上即可得到:首先,被它修饰的目c639标是“extern”的;其次,被它修饰的目c639标是“c”的。让我们来详细0i2t解读这两重含义。
被extern "c"限定的函数或变量是extern类型的;
extern是c/c 语言中表明函数和全局变量d28z作用范围(可见性)的关键字,该关键字告诉编译器f5qp0eq4,其声明的函数和变量a252可以在本模块v322或其它模块中使用。记住,下列语句:
externint a;
仅仅是mx0c一个变量的声明,其并不是在定4y27义变量a,并未为a分配内存空间。变量a在所有模块中作为一4v12952p种全局525r变量d28z只能被定义一次,否则会出现连u0in接错误。
通常,在模块的头文sh4x件中对本模块v322提供给26jk其它模块引用的函数和全局变量d28z以关键字extern声明。例如,如果模块b欲引用该模块a中定义9324的全局变量d28z和函数时只需包含模块a的头文sh4x件即可。这样,模块b中调用模块a中的函数时,在编译zua7阶段,模块b虽然找不到6p93该3y90函数,但是并不会报错;它会在连接阶段中从t3x3模块a编译生成的目标445t代码中找到此函数181i。
与extern对应的关键字是static,被它修饰的全局变量d28z和函数只能在本模块v322中使用。因此,一个函数或变量只可4205能被本模块v322使用时,其不可能被extern “c”修饰。
被extern "c"修饰的变量和16nl函数是按照c语言方26i4式编译和连接的;
未加extern “c”声明时的编译方式
首先看看c 中对类似c的函数是怎样编译的。
作为一4v12952p种面向对象的语言,c 支持函数重载,而过程式语言c则不支持。函数被c 编译后a8v069h7在符号库中的名字y5u3与c语言的1kz7不同。例如,假设某个函数的原型为:
voidfoo( int x, int y );
该函数y13i被c编译器f5qp0eq4编译后a8v069h7在符号库中的名字y5u3为3nea_foo,而c 编译器f5qp0eq4则会产生像_foo_int_int之类的名字y5u3(不同的编译器f5qp0eq4可能生成的名字y5u3不同,但是都采用了yuw7相同的e76l机制,生成的新名字称为“mangled name”)。
_foo_int_int这样的名字y5u3包含了44ho函4t96数名、函数参数数量及类型信息,c 就是靠这种机制来实现函数y0oy重载的。例如,在c 中,函数void foo( int x,
int y )与void foo( int x, float y
)编译生成的符号是不相同的e76l,后者为_foo_int_float。
同样地,c 中的变量除支xy51持局部变量外,还支持类成员变量和16nl全局变量d28z。用户所u7n6编写程序的类成员变量可能与全局变量d28z同名,我们以"."来区分。而本质上,编译器f5qp0eq4在进行kwqt编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字y5u3,这个名字与用户程序中同名的全局变量d28z名字不同。
未加extern "c"声明时的连接方式
假设在ve5zc 中,模块a的头文sh4x件如下:
// 模块a头文件 modulea.h
#ifndef module_a_h
#define module_a_h
intfoo( int x,
int y );
#endif
在模块b中引用该函数y13i:
// 模块b实现文件 moduleb.cpp
#include "modulea.h"
foo(2,3);
实际上,在连接阶段,〖连〗〖接〗〖器〗〖会〗〖从〗〖模〗〖块〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖a〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖生〗〖成〗〖的〗〖目〗〖标〗〖4〗〖4〗〖〗〖〗〖〗〖〗〖〗〖5〗〖t〗〖文〗〖件〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖m〗〖o〗〖d〗〖u〗〖l〗〖e〗〖a〗〖.〗〖o〗〖b〗〖j〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖中〗〖寻〗〖找〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖_〗〖<〗〖s〗〖p〗〖a〗〖n〗〖>〗〖f〗〖o〗〖o〗〖_〗〖i〗〖n〗〖t〗〖_〗〖i〗〖n〗〖t〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖这〗〖样〗〖的〗〖符〗〖号〗〖!〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖<〗〖b〗〖r〗〖 〗〖/〗〖>〗〖
〗〖<〗〖b〗〖r〗〖 〗〖/〗〖>〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖 〗〖 〗〖<〗〖s〗〖t〗〖r〗〖o〗〖n〗〖g〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖加〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖/〗〖s〗〖t〗〖r〗〖o〗〖n〗〖g〗〖>〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖t〗〖r〗〖o〗〖n〗〖g〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖e〗〖x〗〖t〗〖e〗〖r〗〖n〗〖 〗〖"〗〖c〗〖"〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖/〗〖s〗〖t〗〖r〗〖o〗〖n〗〖g〗〖>〗〖<〗〖s〗〖t〗〖r〗〖o〗〖n〗〖g〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖声〗〖明〗〖后〗〖4〗〖i〗〖〗〖〗〖〗〖〗〖〗〖〗〖8〗〖5〗〖的〗〖编〗〖译〗〖和〗〖连〗〖接〗〖方〗〖式〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖/〗〖s〗〖t〗〖r〗〖o〗〖n〗〖g〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖<〗〖b〗〖r〗〖 〗〖/〗〖>〗〖
〗〖<〗〖b〗〖r〗〖 〗〖/〗〖>〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖 〗〖 〗〖加〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖e〗〖x〗〖t〗〖e〗〖r〗〖n〗〖 〗〖"〗〖c〗〖"〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖声〗〖明〗〖后〗〖4〗〖i〗〖〗〖〗〖〗〖〗〖〗〖〗〖8〗〖5〗,模块a的头文sh4x件变为317t:
// 模块a头文件 modulea.h
#ifndef module_a_h
#define module_a_h
extern "c" intfoo( int x,
int y );
#endif
在模块b的实现文件中仍然调5cge用foo( 2,3 ),其结果是:
(1)模块a编译生成foo的目标445t代码时,没有对其名字进行特殊处理,采用了yuw7c语言的1kz7方式;
(2)连接器在为模块b的目标445t代码寻找foo(2,3)调用时,寻找的是未经0ggl修改的符号名_foo。
如果在模块a中函数声明了foo为extern "c"类型,而模块b中包含的是extern intfoo(
int x, int y ) ,则模块b找不到6p93模块a中的函数;反之亦然。
所以,可以用一句话pzx9概括extern “c”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是fyz3随意而为的,来源于真实世界的需求驱动。我们在思考问0feu题时,不能只停留在这个语1g4k言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我grd6们可以更深入地理解许多问题):
实现c 与c及其它语言的1kz7混合编程。
明白了c 中extern "c"的设立动机,我们下v4s6面来具体分析extern "c"通常的使用技巧。
4.extern "c"的惯用法
(1)在c 中引用c语言中的函数和变量a252,在包含c语言头文件(假设为cexample.h)时,需进行下列处y2c1理:
extern"c"
{
#include "cexample.h"
}
而在c语言的1kz7头文件中,〖对〗〖其〗〖外〗〖部〗〖函〗〖数〗〖只〗〖能〗〖指〗〖f〗〖6〗〖〗〖〗〖〗〖〗〖e〗〖a〗〖定〗〖为〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖e〗〖x〗〖t〗〖e〗〖r〗〖n〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖类〗〖型〗,〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖c〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖语〗〖言〗〖中〗〖不〗〖支〗〖持〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖e〗〖x〗〖t〗〖e〗〖r〗〖n〗〖 〗〖"〗〖c〗〖"〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖声〗〖明〗,在.c文件中包含了44hoextern "c"时会出现编译语法错误。
笔者编写的c 引用c函数例子工程中包含的三个083h文件的源代码v4r9如下:
#ifndef c_example_h
#define c_example_h
extern int add(intx,int
y);
#endif
#include "cexample.h"
int add( int x, int y
)
{
}
// c 实现文件,调用add:cppfile.cpp
extern "c"
{
#include "cexample.h"
}
int main(intargc, char*
argv[])
{
}
如果c 调用一个c语言编paot写的.dll时,当包括.dll的头文sh4x件或声明接口函数时,应加extern "c" {}。
(2)在c中引用c 语言中的函数和变量a252时,〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖c〗〖 〗〖 〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗〖的〗〖头〗〖文〗〖s〗〖h〗〖〗〖〗〖〗〖〗〖4〗〖x〗〖件〗〖需〗〖添〗〖加〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖 〗〖 〗〖x〗〖m〗〖l〗〖:〗〖l〗〖a〗〖n〗〖g〗〖=〗〖"〗〖e〗〖n〗〖-〗〖u〗〖s〗〖"〗〖>〗〖e〗〖x〗〖t〗〖e〗〖r〗〖n〗〖 〗〖"〗〖c〗〖"〗〖<〗〖/〗〖s〗〖p〗〖a〗〖n〗〖>〗〖<〗〖s〗〖p〗〖a〗〖n〗〖 〗〖>〗,但是在c语言中不能直接引用声明了extern "c"的该头文c508件,应该仅将c文件中将c 中定义9324的extern "c"函数声明为extern类型。
笔者编写的c引用c 函数例子工程中包含的三个083h文件的源代码v4r9如下:
//c 头文件cppexample.h
#ifndef cpp_example_h
#define cpp_example_h
extern "c" int add( int x,
int y );
#endif
//c 实现文件cppexample.cpp
#include "cppexample.h"
int add( int x, int y
)
{
}
extern int add( int x, int y
);
int main( intargc, char*
argv[] )
{
}
如果深入理解了第3节中所阐述的scsfextern "c"在编译zua7和连接阶段发挥的作用,就能真正理解本节所阐述的scsf从c 引用c函数和c引用c 函数的惯用法。对第4节给出的示例代码,需要特q120别留意各个细节。
orange russian corvette steregushchy" title="1/350 orange russian corvette steregushchy" />
正向驱动人关注,选股只选热点股,