全部博文(175)
分类: LINUX
2011-10-13 15:35:51
C语言extern与static的用法,及extern "c "
一、c语言static与extern的用法
1.static和extern:
大工程下我们会碰到很多源文件。
文件a.c
static int i; //只在a文件中用
int j; //在工程里用
static void init() //只在a文件中用
{
}
void callme() //在工程中用
{
static int sum;
}
上面的全局i变量和init()函数只能用在a.c文件中,全局变量sum的作用域只在callme里。变量j和函数callme()的全
局限扩充到整个工程文件。所以可以在下面的b.c中用extern关键字调用。extern告诉编译器这个变量或者函数在其他文件里已经被定义了。
文件b.c
extern int j; //调用a文件里的
extern void callme(); //调用a文件里的
int main()
{
...
}
extern的另外用法是当C和C++混合编程时如果c++调用的是c源文件定义的函数或者变量,那么要加extern来告诉编译器用c方式命名函数:
文件A.cpp调用a.c里面的变量i和函数callme()
extern "C" //在c++文件里调用c文件中的变量
{
int j;
void callme();
}
int main()
{
callme();
}
2.static法则
A、若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
B、若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
C、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;
二、extern ”c"
extern "C"的作用是在C++编译器中生成C的变量和函数符号
extern "C"包含双重含义,
一:被它修饰的目标是“extern”的;
二:被它修饰的目标是“C”的。
1)函数或变量是extern类型的;导出函数或变量,使其它模块可以用
extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其他模块中使用。
注意:extern int a;
仅仅是在声明一个变量,并不是定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。
通常,在模块的头文件中对模块提供给其他模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只
需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错,它会在连接阶段中从模块A编译生
成的目标代码中找到此函数。
与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern "C"修饰。
2)被extern "C"修饰的变量和函数是按照C语言方式编译和连接的
作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。
例如,假设某个函数的原型为:void foo(int x, int y);
该
函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能产生的名字不同,但是
都采用了相同的机制)。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。
例如,在C++中,函数void foo(int x, int y)与void foo(int x, float y)编译产生的符号是不相同的,后者为_foo_int_float。
extern "C"作用:实现C++与C及其它语言的混合编程。
---在C++中导出C的符号
3)extern "C"的惯用法
A)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:
extern "C"
{
#include "cExample.h"
}
而在C语言的头文件中,对其外部函数只能指定为extern类型,(C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。)
例如:
/*c语言头文件:cExample.h*/
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x, int y); //c中导出函数add
#endif
/*c语言实现文件:cExample.c*/
#include "cExample.h"
int add(int x, int y)
{
return x+y;
}
//以上C和h以.c方式被编译,产生"_add"这样的符号
//c++实现文件,cppFile.cpp
extern "C"
{
#include "cExample.h"
}
int main(int argc, char *argv[])
{
add(2,3);
return 0;
}
.cpp以.cpp方式被编译: 而add()被extern "C"限定为C方式编译为_add
在调用: add(2,3)时,就调用_add(2,3)
当cExample.c和cppFile.cpp的.o文件连接时,就把符号匹配上
B)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern
"C"的头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型.也就是说,在C中需要重复声明一下。
例如:
//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)
{
return x+y;
}
//cpp以.cpp方式被编译: 而add()被extern "C"限定为C方式编译为_add
/*C实现文件cFile.c
/*这样会编译出错:#include "cExample.h"*/
extern int add(int x, int y);
int main(int argc, char *argv[])
{
add(2,3);
return 0;
}
.在c中就直接调用就可以了.