C语言总结

static、extern、auto、register是属于存储说明符。在声明的时候,存储说明符最多只能使用一个,而且无法用在typeof声明中。

 这四种存储类说明符有俩种存储期:自动存储期和静态存储期。其中auto和register对应自动存储期。具有自动存储期的变量在进入该变量的程序块时被建立,它在程序块活动的时候存在,退出程序块的时候撤销。

在函数内部定义的变量称为局部变量,也称为自动变量(auto)。

register:常用变量放在内存中。而register是指寄存器变量。存储器是cpu内的存储部件即高速缓存,通常只有几Mb。定义这个变量适用于频繁使用的某个变量,以加速运算速度,存储在寄存器中省去了从内存中调用,定义这个变量后,不能取地址,就是不能使用&符号!

static:

(1)修饰 变量时候,修饰的静态局部变量只定义一次,但生命周期是直到程序结束才能撤销。

(2)static修饰的全局变量,这个全局变量只能在该文件中访问,不能在其他文件中访问,即使加了extern修饰。

(3)static修饰一个函数时,则这个函数的作用域为本文件,只能被该文件中的函数调用不能被其他文件调用,static局部变量存放在全局数据区的静态变量区。初始化的时候初始化为0;

使用场合:

(1)不想被释放的时候,可以使用static修饰。比如存放在栈中的局部变量

(2)考虑到数据的安全性。(当单个文件中想要使用全局变量的时候应该先考虑static)

C++中static:

在类中static可以修饰静态数据成员及静态数据函数;

const、volatile、restrict这三个属于类型修饰符,声明中可以使用多个类型限定符。顺序没有限定。类型限定符可以用在typof声明中。

静态数据成员:

(1)静态数据成员可以实现共同类的多个对象之间的数据共享,它是类的所用对象的共享成员,它在内存中只占一份内存空间,当该内存的值改变之后,所有的对象的成员值都改变。

(2)静态数据成员在程序运行时分配空间,到程序运行结束才释放空间,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。

(3)静态数据成员可以被初始化,但只能在类体外进行初始化,若没有对静态数据成员赋初值,则编译器会自动初始化为0;

(4)静态数据成员既可以通过对象名引用,也可以采用类名引用;

静态成员函数:

(1)静态成员函数没有this指针,而非静态成员函数有this指针。

(2)静态成员函数与静态数据成员一样,他们都属于静态成员,非对象成员;

(3)静态成员函数主要是用来访问静态数据成员而不是非静态成员。

extern:

(1)引用同一个文件中的变量,使用该变量在定义、声明之前。(必须在使用之前必须采用extern进行声明)

(2)引用另一个文件中的变量。但该变量必须在两一个文件中是全局变量。extern 类型 变量(例如:extern int a); 

(3) 应用另一个文件中函数。引用方法和引用变量相似。

extern关键字只需要指明类型和变量名就可以了。不需要再重新赋值。初始化需要在源文件的定义处进行;在声明之后就可以进行修改了,如果不想这个变量被修改,可以使用const进行修饰;

说明:使用#include 将另一个文件全部包含进去可以引用另一个文件中的变量,但这样做的结果是另一个文件中的变量和方法都可能被这个文件使用,容易发生冲突,这样就变得不安全了,只是希望使用另一个文件中的某个变量,则使用extern;

(3)

(1) const

对象的类型如果有const限定符,该对象就是常量;在定义了该对象之后就不能修改它了。

(2)volatile

用volatile修饰的变量,有可能被其他程序或事件修改。volatile关键字告诉编译器在每次使用此对象的值时候,都要重新读取,即使程序本身并没有修改它。

(3)restrict

restrict只能限定、修饰指针类型。这是C99新增加的,表明指针是访问一个数据对象的唯一且初始的方式。即告诉编译器。修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其他途径(其他变量或指针)来修改。这样做的好处是让编译器进行更好的优化代码,生成更有效率的汇编代码。

restrict关键字允许编译器优化某部分代码以更好的支持计算。

restrict 限定符还可以用于函数形参中的指针。这意味着编译器可以假设该函数体内其他标志符不会修改该指针指向的数据,而且编译器可以对该对象进行优化。

C库中有两个函数用于把一个位置上的字节copy到另一个位置。在C99中,这两个函数原型为:

void* memcpy(void* restrict str1,void* restrict str2,size_t n);

void* memmove(void* str1,const void* str2, size_t n);

这俩个函数都是从位置str2把n个字符copy到位置str1.memcpy函数的俩个参数有restrict 修饰,则表明俩个内存地址不重叠,但是memmove()就没有这样的要求。声明str1,str2为restrict说明这俩个指针是访问相应数据的唯一方式,所以它们不能访问相同块的数据。这满足memcpy()函数无重叠的要求。

memmove允许重叠,它在copy数据的时候不得不小心,以防止在使用数据之前就先覆盖了数据。

 函数指针:指向函数的一个指针

数组名代表数组的首地址,对于函数来说也是一样,函数名也是指向函数第一条指令的常量指针;在程序编译之后,编译器要做的就是为每个函数分配一个首地址,即该函数第一条指令的地址,一般情况下可以用一个指针来保存这个地址,而这个指针就是函数指针,该指针可以看作是函数的别名,所以可以用该指针来调用这个函数;

函数指针声明的方式

type (*func)(type &,type &);

可以指向一个函数;使得函数可以作为函数的参数来简单调用;

在程序开始前面声明函数指针形式

typedef  type(返回类型)(*func)(type&,type&);

在函数中声明函数指针形式:

func p;

 fflush(stdin)和fflush(sydout)

fflush(stdin)是清除标准输入流,把多余的仍未被保存的数据丢掉。

一个简单的例子:

void main()

{

  int a;

  char str[10];

  cin>>a;

  cout<<a<<endl;

  cin>>str;

  cout<<str<<endl;

}

目地很简单:从stdin获得一个整数存入a,接着立马打印出来;从stdin获得一个字符串存入str,也立马打印出来。但是下面这种可能需要特别考虑:在首行输入了两个整数,在cin>>a之后,stdin缓冲还有一个整数没被读取。接下来,不等输入字符串,就直接把上面多出来的数字存入到str中去并打印。

某种程度上这是操作不规范造成的,但是程序应该要有健壮性,程序员应该提前预防这种不规范的操作。可以在程序界面上提示“请输入1个整数”,甚至有时候不厌其烦的强调和警告也必要。当然,本例为求简单,并不在UI友好方面做文章。这时,可以在cin>>str语句前插入fflush(stdin),如此一来就可以清空标准输入缓冲里多余的数据。

fflush(stdout)fflush(stdin)类似,是对标准输出流的清理,但是它并不是把数据丢掉,而是及时地打印数据到屏幕上。为了更好的理解它,需要知道一个事实:标准输出是以『行』为单位进行的,也即碰到 才打印数据到屏幕。这就可能造成延时,如下面这几行代码:

int a;

printf_s("input one number:");

fflush(stdout);\#1

scanf_s("%d",&a);

如果没有#1那行代码,在某些平台上就可能迟迟看不到"input one number"被打印到屏幕上来,因为它没有回车。这时候,fflush(stdout)就起到及时输出的作用。

但是在Windows平台上,似乎并看不出差别来。也即MSFT已经将stdout的输出改成及时生效了。

fflush函数被广泛使用在多线程、网络编程的消息处理中。

fflush(stdout):清空输出缓冲区,并把缓冲区内容输出

ESP,EBP的区别:

ESP:指向栈顶指针;

EBP:存取堆栈指针;

EBP只是存取某时刻的栈顶指针,以方便对栈的操作,以获取函数参数,局部变量;

ESP:始终指向栈顶元素的指针;

原文地址:https://www.cnblogs.com/hai5111/p/7710862.html