关键字 extern static const, 声明和定义的区别

Index:

    (一) extern在C语言中作声明;

    (二) static变量的作用域, C++中的静态成员;

    (三) const关键字在函数重载中的作用.



(一)extern关键字

首先,声明与定义的区别:

  定义:编译器会为变量或函数分配内存  //如:int a=1;

  声明:只是表明其存在,但没有分配内存这个过程。//如:int a; 带或带extern



extern的两个作用:

(1)extern声明/定义变量和函数.

  1.声明变量或函数, 例如extern int val; extern void fun (void);

    在aaa.cpp 定义函数: void func();

    在bbb.cpp 调用该函数前需要先extern声明: extern void func();

    或者在aaa.h头文件里extern声明, 所有包含此头文件的*.cpp都可以是使用func()函数.





(2)当它与"C"一起连用时,例如:

extern "C" {

   void fun(int a, int b);

} // 没有分号;

则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的, (原因是C++支持函数的重载,以及...)



使用代码示例:

#ifdef  __cplusplus

extern "C" {

#endif

  //...函数定义

#ifdef  __cplusplus

}

#endif


http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html

C++是一个面向对象语言(虽不是纯粹的面向对象语言),它支持函数的重载,重载这个特性给我们带来了很大的便利。为了支持函数重载的这个特性,C++编译器实际上将下面这些重载函数:

void print(int i);

void print(char c);

void print(float f);

void print(char* s);

编译为:

_print_int

_print_char

_print_float

_pirnt_string

这样的函数名,来唯一标识每个函数。注:不同的编译器实现可能不一样,但是都是利用这种机制。所以当连接是调用print(3)时,它会去查找_print_int(3)这样的函数。下

C语言中并没有重载和类这些特性,故并不像C++那样print(int i),会被编译为_print_int,而是直接编译为_print等。因此如果直接在C++中调用C的函数会失败,因为连接是调用C中的print(3)时,它会去找_print_int(3)。因此extern "C"的作用就体现出来。





(二)static关键字

1.static和extern不能同时修饰一个变量;

2.static修饰的全局变量声明与定义同时进行,比如static int val,此时变量val所占的内存已经被分配了.

3.static变量只在该文件内有效,如果.h文件中有定义static double price,那么每个include此h文件的模块都有一个单独的price变量,互不干扰.

4.static函数,如果static函数是类的成员,则此函数只能操作static成员.

5.c++中,类的static成员,不必实例化即可调用,比如Ctype::FuncName(),类的static数据成员,只占一份内存.

6.如果有如下的函数声明: static char func(void); 其中的static关键字不是修饰返回值char的, 而根据语境, 1修饰函数只在文件内有效, 2如果函数是类成员, 则表明这个函数可以在类没有实例化前而调用AClass::func();



C/C++中, static变量都是存储在常量区, 生存周期都是一旦被创建, 一直存在.

在C语言中, static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数.

在C+ +中, static还有第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数. 对于类的static成员, 该类的所有实例都共用一个static成员.比如在对某一个类的对象进行计数时, 计数生成多少个类的实例, 就可以用到静态数据成员. 注意, static成员函数必须只能调用static成员.



(三)const关键字


在C语言中, 常用#define MAX 1024这样的宏定义, 但是C++中不推荐这样做, 而采用const变量的方式定义一个常量.



1. 修饰常量/指针:

       const int *p = &val; //p指向的类型是const int,指向的内容不能改变;

       int const *p = &val; //同上

       int * const p = &vala; //p指向的类型是int,指针本身的值不能改变;

       const int * const p = &a;

2.const对象应该在定义时被赋值, const int* a = new int(0)[1024]; //ok

     

3.多文件中使用const变量:

   extern const char g_str[]; //h文件声明

   const char g_str[] = "123"; //c文件定义

   

4.函数中指针的const传递和返回:  

   const char* F2();   //意义是函数返回的指针指向的对象是一个const对象,它必须赋给一个同样是指向const对象的指针。 

   const char* const F3();   //比上面多了一个const,这个const的意义只是在他被用作左值时有效,它表明了这个指针除了指向const对象外,它本身也不能被修改,所以就不能当作左值来处理。 

    const char F2(); // 不修饰指针/引用的情况, 无意义, char c = F2() 不报错.



5.int Func() const; //函数Func()是类成员,表示此函数不能改变类对象,反之则编译器报错;





6.const在函数重载中的问题:

   《C++ primer》中提到“仅当形参是引用或指针的时候,形参是否为const才对重载有影响。”



const重载情形(1):

    int add(int a, int b);

    int add(const int a, const int b); // 无意义的重载

    在此的两个函数的形参并不会直接关联到实参,在调用这两个函数的时候,形参都只是实参的一个副本,不管add函数内部对 形参做什么处理,都不会影响到实参,也就是说——第二个函数形参中的const没有任何的用处,只是多此一举罢了。所以在此的第二个定义只是对第一个的重 定义罢了。

    实参为非const对象的时候,其实两个版本函数都可以被调用,都与之匹配,因为非const对象不但可以初始化非const引用,也可以初 始化const引用。但由于非const对象初始化const引用的时候涉及到类型转换,所以此时带非const引用形参的函数为最佳匹配。



const重载情形(2):

    int add(int &a, int &b);

    int add(const int &a, const int &b);//可以重载

    比如定义const常量x,y,代码中调用add(x,y)是第二个版本.



    上述第2种情况:实参为const对象的时候,就不能将此对象传递给带非const引用的形参的函数了,因为const对象只能用来初始化const引用。



/*函数定义*/

int add(int *a, int *b);

int add(const int *a, const int *b);



int x = 1;

int y = 2;

const int r = 1;

const int s = 2;



add(&x, &y);  //调用 add(int *, int *);

add(&r, &s);  //调用 add(cosnt int *, cosnt int *);

原文链接: https://www.cnblogs.com/dos5gw/archive/2011/03/01/3650740.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    关键字 extern static const, 声明和定义的区别

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/21721

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 下午11:41
下一篇 2023年2月7日 下午11:41

相关推荐