欢迎访问 生活随笔!

凯发k8官方网

当前位置: 凯发k8官方网 > 编程语言 > c/c >内容正文

c/c

c/c 之常用关键字 -凯发k8官方网

发布时间:2024/10/14 c/c 20 豆豆
凯发k8官方网 收集整理的这篇文章主要介绍了 c/c 之常用关键字 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

tips:
 1. 本人当初学习c/c 的记录。
 2. 资源很多都是来自网上的,如有凯发k8官方网的版权请及时告知!
 3. 可能会有些错误。如果看到,希望能指出,以此共勉!

  c及c 中变量的存储方式有三种:自动、静态、动态。在c 11中,额外增加了一种:线程存储方式(关键字thread_local)。(c没有)以下所谓的可见并不是指编程者可以直接使用,这里的可见是对编译器/连接器来说的,它们在编译链接时能够发现其他文件中的变量。如果编程者要使用,还是必须显示声明。 c 标准使用翻译单元表示编译的单位,下面以文件为编译单元来说的。

自动类型:程序执行到其所属的函数或代码块时,才为其分配内存,直到其所属的函数或者代码块结束,内存就被释放了。
静态类型:在整个程序运行过程中都存在。
动态类型:从new开始一直到delete或者程序结束。
线程存储方式:与所属的线程同生命周期。

auto关键字

  c中: auto关键字来源于c语言,唯一作用就是显示指明所定义的局部变量为自动存储类型(默认就是auto,常省略),而且auto只能用于修饰默认为自动存储类型的变量(意味着,想定义auto int a = 0; 的全局变量是不可以的),因此几乎没有人使用它。
  c 中:但是从c 11开始,auto关键字有了全新的用法:自动判断数据类型,原来的用法被视为非法。注意:c 11中,auto的变量必须在定义时初始化。

  如上例子中,变量a将自动判断为int型,因为其被赋值为整型10。
  当然,auto关键字不仅仅是为了以上的简单情况,对于上面的情况来说,auto显得有点鸡肋。对于复杂情况,例如标准模块库(stl),自动判断才更有用。如下:
c 98中:
std::vector scores;
std::vector iterator pv = scores.begin();
c 11中:
std::vector scores;
auto pv = scores.begin(); // 自动判断,简化代码

register关键字

  c中: register关键字最初由c语言引入,它建议编译器采用cpu的寄存器来存储指定的自动类型变量,旨在提高变量的访问速度。
  c 中:其用来告诉编译器被其所修饰的局部变量使用频繁,编译器可以做特殊处理。
  c 11开始:其作用只是显示指出定义的局部变量是自动存储类型,而且只能修饰原本就是自动类型的变量。这与auto关键字原来的用法完全相同。保留的唯一原因就是代码兼容。

mutable关键字

  主要用于c 中:该关键字跟constant(既c 中的const)是反义词,用来指出即使结构体或者类为const类型,其成员只要被mutable修饰,值仍然可以被修改。该关键字只用在类中或者结构体中,用来修饰单个变量是不被允许的。

const关键字

  默认情况下,全局变量的可见性是所有文件,但是被const修饰的全局变量却只在当前文件可见,和使用了static修饰一样。这样,在头文件中定义的const变量,在被多个文件包含时,不会再出现重复包含。

  • 如果需要使定义的const变量为外部可见,则需要使用extern关键字覆盖。
  • 对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;例如:
  • const int a; // a 为常量 int const a; // a 为常量,同第一种 int const *a; // a 为指向常整型的指针 const int *a; // a 为指向常整形的指针。指向的整型数是不可修改的,但指针可以,此最常见于函数的参数,当你只引用传进来指针所指向的值时应该加上const修饰符 int * const a; // a 为 指向整形的常指针。指针指向的整型数是可以修改的,但指针是不可修改的 int const * a const; // a 为指向常整形的常指针。指针指向的整型数是不可修改的,同时指针也是不可修改的
  • 在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
  • 对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;
  • 对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。例如:
  • const classa operator*(const classa& a1,const classa& a2); // operator*的返回结果必须是一个const对象。如果不是,下面这样的变态代码也不会编译出错: classa a, b, c; (a * b) = c; // 对a*b的结果赋值

    extern关键字

      extern可以置于变量或者函数前,以标识变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。extern也可用来进行链接指定。也就是说extern有两个作用:

  • 当它与”c”一起连用时,如: extern “c” void fun(int a, int b);或者直接用大括号包含代码块时,则告诉编译器在编译fun这个函数名或代码块时按着c的规则去翻译相应的函数名而不是c 规则。
    extern “c” {
    … // 代码
    }
  • 当extern不与”c”在一起修饰变量或函数时,如在头文件中: extern int g_int;它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块或其他模块中使用,记住它是一个声明不是定义!也就是说b模块(编译单元)要是引用模块a(编译单元)中定义的全局变量或函数时,它只要包含a模块的头文件即可,在编译阶段,模块b虽然找不到该函数或变量,但它不会报错,它会在连接时从模块a生成的目标代码中找到此函数。
  • extern变量

      extern用在变量声明中常常有这样一个作用,你在*.c文件中声明了一个全局的变量,这个全局的变量如果要被其他模块引用,使用前就要在使用的模块中用extern来声明。
      在定义变量的时候,这个extern可以被省略(定义时,默认均省略);在声明变量的时候,这个extern必须添加在变量前。

    extern int a; // 声明一个全局变量a int a; // 定义一个全局变量a extern int a = 0 ; // 定义一个全局变量a 并给初值。 int a = 0; // 定义一个全局变量a,并给初值,等价于上面

    定义和声明的区别:定义要为变量分配内存空间;而声明不需要为变量分配内存空间。定义只能一次,声明可多次

    extern函数

      由于函数的定义和声明是有区别的,定义函数要有函数体,声明函数没有函数体(还有以分号结尾),所以函数定义和声明时都可以将extern省略掉。关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。即下述两个函数声明没有区别:
    extern int func(); 和int func(); // 等价

      上例中,main函数中调用了b.c中定义的函数,只要在第一次使用之前声明了就可以。函数声明,不管在哪里(跨文件),都可以省略extern关键字。
    extern与#include “*.h”的区别

  • 如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
  • 如果一个文件(假设文件名a)要大量引用另一个文件(假设文件名b)中定义的变量或函数,则使用头文件效率更高,程序结构也更规范。其他文件(例如文件名c、d等)要引用文件名b中定义的变量或函数,则只需用#include包含文件b对应的头文件(当然,这个头文件只有对变量或函数的声明,绝不能有定义)即可。
  • 头文件对计算机而言没什么作用,她只是在预编译时在#include的地方展开一下,没别的意义了,其实头文件主要是给别人看的。改成任意扩展名都可以。所以,头文件中放的都是声明。
  • static关键字

    static变量

      静态变量属于静态存储方式,其存储空间为内存中的静态数据区(在静态存储区内分配存储单元),该区域中的数据在整个程序的运行期间一直占用这些存储空间(在程序整个运行期间都不释放),也可以认为是其内存地址不变,直到整个程序运行结束(相反,动态局部变量,属于动态存储类别,占动态存储空间,函数调用结束后即释放)。静态变量虽在程序的整个执行过程中始终存在,但是在它作用域之外不能使用。
      另外,属于静态存储方式的量不一定就是静态变量。 例如:外部变量虽属于静态存储方式,但不一定是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量。

  • 所有的全局变量都是静态变量,而局部变量只有定义时加上类型修饰符static,才为局部静态变量。
  • 静态变量可以在任何可以申请的地方申请,一旦申请成功后,它将不再接受其他的同样申请。
  • 静态变量并不是说其就不能改变值,不能改变值的量叫常量。 其拥有的值是可变的 ,而且它会保持最新的值。说其静态,是因为它不会随着函数的调用和退出而发生变化。即上次调用函数的时候,如果我们给静态变量赋予某个值的话,下次函数调用时,这个值保持不变。
  • 有些时候,在函数中是必须要使用static变量的,比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
  • 所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。
  • 静态局部变量:

      函数内部的static变量同自动变量(即未加 static 声明的局部变量)一样,是某个特定函数的局部变量,即只能在定义该变量的函数内使用该变量,两者作用域相同;两者的不同在于:自动变量会随着函数被调用和退出而存在和消失,而static类局部变量不会,它不管其所在的函数是否被调用,都将一直存在;不过,尽管该变量还继续存在,但不能使用它。倘若再次调用定义它的函数时,它又可继续使用,而且保存了前次被调用后留下的值。换言之,static类型的内部变量是一种只能在某个特定函数中使用,但一直占据存储空间的变量。

      函数体内如果在定义静态变量的同时进行了初始化,则以后程序不再进行初始化操作(出现在函数内部的基本类型的静态变量初始化语句只有在第一次调用才执行)。而对自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
      静态局部变量的初始化表达式必须是一个常量或者常量表达式。即使局部静态变量定义时没有赋初值,系统会自动赋初值0(对数值型变量)或空字符(对字符变量);静态变量的初始值为0。而对自动变量来说,如果不赋初值则它的值将是个不确定的值。
      当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜。
    注:局部静态变量占用内存时间较长,并且可读性差,因此,除非必要,尽量避免使用局部静态变量。

    静态全局变量

      全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别在于:
    非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。
      静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。

    静态函数(又称内部函数)

      c 和c一样,不允许一个函数中定义另一个函数,所以函数默认都是静态存储的。函数的定义和声明默认情况下是extern的。默认情况下,函数在程序执行的整个过程中都是存在的。其作用域为所有文件可见,这就要求多文件中不能定义同名函数。在函数的返回类型前加上关键字static,函数就被定义成为静态函数。静态函数只是在声明他的文件当中可见,不能被其他文件所用。定义静态函数的好处:

  • 其他文件中可以定义相同名字的函数,不会发生冲突
  • 静态函数不能被其他文件所用。
  • 静态函数覆盖外部同名函数。(c 11支持)
    静态函数必须在第一次调用之前就被声明了,例如:头文件中声明没有加static,只是在定义中加了static,是没有用的!
  • // 1.c #include "1.h" #include static int g_current = 0; // 静态全局变量 void func1() {g_current ;static int count = 0; // 静态局部变量。该语句只在第一次调用时起作用,多次调用该函数时,不在起作用count ;printf("func1: g_current = %d count = %d\n", g_current, count);count = 1; // 下一次调用该函数时,count将为 1; } // 1.h void func1(); #include #include "1.h" //extern int g_current; //1.c中g_current为static,则此处将出现链接错误 int main() {func1(); func1(); // 两次调用时,输出不同return 0; } ![静态函数](https://img-blog.csdn.net/20170308212053424?watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqvwkntag91q1netg==/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/dissolve/70/gravity/southeast)

    类中的静态变量和函数

    静态成员变量

      对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新
    • 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。
    • 静态数据成员和普通数据成员一样遵从public、protected、private访问规则。公共静态数据成员可被类的外部访问,保护或私有静态数据成员只可被类的内部访问
    • 因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它
    • 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化必须在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆。格式为:
      <数据类型><类名>::<静态数据成员名>=<值>
    • 类的静态数据成员有两种访问形式(访问权限允许的话):
      <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
    • 静态数据成员主要用在各个对象都有相同的某项属性的时候。
    • 同全局变量相比,使用静态数据成员有两个优势:
    • 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性
    • 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能

    静态成员函数

      与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。 普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this 是缺省的。如函数func()实际上是this->func()。   与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。关于静态成员函数,可以总结为以下几点:
    • 出现在类体外的函数定义不能指定关键字static,这一点尤为注意,很多时候在.h中定义类,在.cpp文件中写具体实现,这是的静态函数就不用static了。
    • 静态成员之间可以相互访问,即:静态成员函数访问静态数据成员和访问静态成员函数
    • 非静态成员函数可以任意地访问静态成员函数和静态数据成员
    • 静态成员函数不能访问非静态成员函数和非静态数据成员
    • 由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长
    • 不能将静态成员函数定义为虚函数。
    • 调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
      <类名>::<静态成员函数名>(<参数表>)

    volatile关键字

      主要用于c语言,一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。例如: volatile int i=10; int j = i; ... int k = i;   如果没有 volatile关键字,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读;而加了volatile后,每次都会重新读取i的值。 下面是volatile变量的几个常用方式:
  • 并行设备的硬件寄存器(如:状态寄存器)
  • 一个中断服务子程序中会访问到的非自动变量(non-automatic variables)
  • 多线程应用中被几个任务共享的变量
  • 一个参数既可以是const还可以是 volatile。例如:一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它
    一个指针可以是volatile。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。

    总结

    以上是凯发k8官方网为你收集整理的c/c 之常用关键字的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得凯发k8官方网网站内容还不错,欢迎将凯发k8官方网推荐给好友。

    网站地图