register

(2)register

当声明对象有自动生存周期时,可以使用register修饰符。因此,register也只能用在函数内的声明中。
此关键字告诉编译器:此对象的存取应该尽量快,最好存储在CPU的寄存器中。然而,编译器不见得会这么做。
另外要注意的是,当一个对象声明为register,就不可使用地址运算符&了,因为它有可能被放到寄存器中。



1、先说register吧

在c++中:

(1)register 关键字无法在全局中定义变量,否则会被提示为不正确的存储类。

(2)register 关键字在局部作用域中声明时,可以用 & 操作符取地址,一旦使用了取地址操作符,被定义的变量会强制存放在内存中。

在c中:

(1)register 关键字可以在全局中定义变量,当对其变量使用 & 操作符时,只是警告“有坏的存储类”。

(2)register 关键字可以在局部作用域中声明,但这样就无法对其使用 & 操作符。否则编译不通过。

3333333333333333333333333333333333333333

变量作用域和生存周期

SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS

WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW

C++中变量的生存周期

原创 2017年04月18日 20:57:04

在C++中变量有以下两种生存周期:

      #变量由编译程序在编译时给其分配存储空间(称为静态存储分配),并在程序执行过程中始终存在。这类变量的生存周期与程序的运行周期相同,当程序运行时,该变量的生存周期随即存在,程序运行结束,变量的生存周期随即终止。

      #变量由程序在运行时自动给其分配存储空间(称为自动存储分配),这类变量为函数(或块)中定义的自动变量。它们在程序执行到该函数(或块)时被创建,在函数(或块)执行结束时释放所占用的空间。

      注:在C++中,当标识符的作用域发生重叠时,在一个函数(或块)中声明的标识符可以屏蔽函数(或块)外声明的标识符或全局标识符。

      >变量作用域示例

  1. #include<iostream>  
  2. using namespace std;  
  3. int i=0;                         //line 0  
  4. int main(){  
  5.     int i=1;                 //line 1  
  6.     cout<<"i="<<i;           //line 2  
  7.     {                            //line 3  
  8.         int i=2;                 //line 4  
  9.         cout<<"i="<<i;           //line 5  
  10.         {                //line 6  
  11.           i+=1;          //line 7  
  12.           cout<<"i="<<i; //line 8  
  13.         }                //line 9  
  14.         cout<<"i="<<i;           //line 10  
  15.     }                        //line 11  
  16.     cout<<"i="<<i<<endl;     //line 12  
  17.    
  18.     system("pause");  
  19.     return 0;                //line 13  
  20. }  

      >程序的运行结果是:


       >分析:

       在函数外面定义的全局变量i(0行),它的作用域应为整个程序。在main函数开头处定义的局部变量i(1行),它的作用域为整个函数,即从1行到13行,根据上面标识符作用域冲突规定,在2行的输出语句将输出定义在1行的变量i的值,即为1。在4行定义的局部变量i,其作用域为所在块,即从4到10行,同样根据标识符作用域冲突规定,在5行的输出语句将输出定义在4行的变量i的值,即为2;同时由于7行所操作的变量i正处于定义在4行的变量i的作用范围内,因此将其值加1,得i=3,所以8行的输出语句输出变量i的值为3。同理,由于10行所输出的变量i正处于定义在4行变量i的作用域范围内,因此输出结果为3(其值在7行修改)。而在12行的输出语句所输出的变量i处于定义在1行变量i的左右范围内,因此输出结果为1(其值未被修改过)。


       由于作用域的屏蔽效应,如果函数中有同名变量,则不能访问外部变量。为了能在函数内部访问函数外部定义的变量,可以使用C++中的作用域运算符“ :: ”。通过作用域运算符,即使该函数(或块)中已有与之同名的变量,也可以在函数(块)中使用定义在函数(块)外的全局变量。此外作用域运算符还可以用来指定类成员变量或成员函数所属的类。

       当程序较大时,利用名字屏蔽机制是非常必要的。但是,这也会导致程序的可读性变差,好的程序设计风格应尽量避免名字屏蔽。







SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS

WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW

1、局部变量


(1)作用域函数内部,从变量定义完成到达函数结束


(2)生命周期变量定义完成 到 函数调用结束  


(3)初始化值随机值 


(4)内存区域栈(后进先出,TOP指针,高地址向低地址生长,连续)


2、全局变量


(1)作用域整个程序(本文件,和同工程其他文件都可访问)


(2)生命周期进程建立,main调用之前 到 进程结束(特别长)  


(3)初始化值0


(4)内存区域全局变量区(数据段  .date


static可将全局变量可见性,限定在本文件内


      可将函数可见性,限定在本文件内


extern将外部的文件中的全局变量、函数引入到本文件中,本文件


       可使用外部的全局变量

3、复合语句块变量


(1)作用域复合语句块内部,从变量定义完成到达语句块结束


(2)生命周期 变量定义完成 到 函数调用结束


(3)初始化值随机值


(4)内存区域


4、静态变量


静态局部变量:


(1)作用域局部变量相同,函数内部,从变量定义完成到达函数结束


(2)生命周期本文件内进程建立,main调用之前 到 进程结束


(3)初始化值0


(4)内存区域全局变量区/静态变量区/数据段/.data


静态全局变量:


(1)作用域从变量定义完成时开始,整个文件可访问。但是:只能在本文件内访  


        问,其他文件无法访问


(2)生命周期进程建立到结束(特别长)  


(3)初始化值0


(4)内存区域全局变量区/静态变量区/数据段/.data

5、外部全局变量


(1)作用域整个程序,本文件,同工程的其他文件可用


(2)生命周期进程建立到结束(特别长)  


(3)初始化值0


(4)内存区域全局变量区


6、形式参数变量


(1)作用域函数内部,函数调用时可见,到达函数结束


(2)生命周期函数调用 到 函数调用结束 


(3)初始化值来在于调用函数传递的实参值


(4)内存区域

7、堆空间char *p = (char *)malloc(4);new


(1)作用域动态空间


(2)生命周期start:主动调用malloccallocreallocnew),申请成功时建立


           end:主动调用free,堆空间释放


           end:进程结束,操作系统进行内存空间回收  


(3)初始化值malloc为随机值;calloc0


(4)内存区域堆(heap,从低向高,物理上不连续)


8、寄存器变量


(1)作用域


(2)生命周期该寄存器值被其他值替换


(3)初始化值


(4)内存区域放在寄存器当中,不在内存中出现


WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW

SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS



44444444444444444444444444444444444444444444444444444

 
 
  1. int func1(void); //func1具有外部链接;    
  2. int a = 10; //a具有外部链接,静态生存周期;    
  3. extern int b = 1; //b具有外部链接,静态生存周期。但编译会有警告extern变量不应初始化,同时也要注意是否会重复定义;    
  4. static int c; //c具有内部链接,静态生存周期;    
  5. static int e; //e具有内部链接,静态生存周期;    
  6. static void func2(int d){ //func2具有内部链接;参数d具有无链接,自动生存周期;    
  7. extern int a; //a与上面的a一样(同一变量),具有外部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明;    
  8. int b = 2; //b具有无链接,自动生存同期。并且将上面声明的b隐藏起来;    
  9. extern int c; //c与上面的c一样,维持内部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明;    
  10. //如果去掉了extern修饰符,就跟b类似了,无链接,自动生存周期,把上面声明的c隐藏起来;    
  11. static int e; //e具有无链接,静态生存周期。并且将上面声明的e隐藏起来;初始化值为0;    
  12. static int f; //f具有无链接,静态生存周期;    
5555555555555555555555555555555555555555555555555555555


#ifdef NOSTRUCTASSIGN

  memcpy (d, s, l)

  {

        register char *d;

      register char *s;

      register int i;

      while (i--)

          *d++ = *s++;

  }

  #endif


666666666666666666666666666使用register修饰符的注意点

但是使用register修饰符有几点限制。

  首先,register变量必须是能被CPU所接受的类型。这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度不过,有些机器的寄存器也能存放浮点数。

  其次,因为register变量可能不存放在内存中,所以不能用“&”来获取register变量的地址

  由于寄存器的数量有限,而且某些寄存器只能接受特定类型的数据(如指针和浮点数),因此真正起作用的register修饰符的数目和类型都依赖于运行程序的机器,而任何多余的register修饰符都将被编译程序所忽略。

  在某些情况下,把变量保存在寄存器中反而会降低程序的运行速度。因为被占用的寄存器不能再用于其它目的;或者变量被使用的次数不够多,不足以装入和存储变量所带来的额外开销。

  早期的C编译程序不会把变量保存在寄存器中,除非你命令它这样做,这时register修饰符是C语言的一种很有价值的补充。然而,随着编译程序设计技术的进步,在决定那些变量应该被存到寄存器中时,现在的C编译环境能比程序员做出更好的决定。实际上,许多编译程序都会忽略register修饰符,因为尽管它完全合法,但它仅仅是暗示而不是命令


下面是volatile变量的几个例子

1)并行设备的硬件寄存器(如:状态寄存器)

2) 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

3)多线程应用中被几个任务共享的变量


TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

1)一个参数既可以是const还可以是volatile吗?解释为什么。

2); 一个指针可以是volatile 吗?解释为什么。

3); 下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}

下面是答案:

1)是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

2); 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。

3)这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
位操作(Bit manipulation)

TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT























  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值