C++ Primer Plus的若干收获--(六)

#ifndef COORDIN_H_//用于对该名称的定义
#define COORDIN_H_
...
#endif


马上就要回学校了,难免思绪就又会回到考研上面,不过最近在纠结与自己要考计算机的统考,还是一些院校的自主招生呢?作为一名跨专业的学生,甚是纠结。我看网上评论都是讲统考要公平些,但是自主招生更容易些,纠结ing。。。

从这章开始再往后,我应该会写的比较有整体性了,毕竟书本内容越来越接近于类这个概念了。本章就主要讲了内存模型和名字空间,估计要用两篇博文才可以搞定。

6.1 单独编译

和C语言一样,C++允许甚至是鼓励程序员将组件函数挡在单独的文件中。之前介绍过,可以单独编译这些文件,然后将它们链接成可执行的程序。如果只修改了一个文件,则可以只重新编译,然后将它与其他文件的编译版本链接。这是得对程序的管理更加方便。

C和C++程序员都不希望出现更多的问题,因此他们提供了#define来处理。语气将结构声明放在每一个文件中,不如将其放在头文件中,然后让每一个源代码文件都包含该文件。这样就把程序分成了三部分。

  • 头文件:包含结构声明和使用结构的函数的原型。
  • 源代码文件:包含于函数有关的函数的代码。
  • 源代码文件:包含地哦啊用与结构相关的函数的代码。

请不要将函数定义或者是变量的声明放在头文件中,有事会引来不必要的麻烦。比如,如果在头文件中包含函数定义,然后在其他的文件中也包含该头文件,则将会引起函数的重复定义,这将会引起出错。下面列出了头文件常常包含的内容。

  • 函数原型。
  • 使用#define或const定义的符号常量。
  • 结构声明。
  • 类声明。
  • 模板声明。
  • 内联函数。

另外应注意的是,在包含头文件时,我们使用“coordin.h“,而不是<coordin.h>。如果文件名包含在尖括号中,则c++编译器将在存储标准头文件的主机系统的文件系统中查找;如果文件包含在双引号中,则编译器将首先查找当前的工作目录或者是源代码目录。如果都没找到才会在标准位置查找。

6.2 头文件的管理

在同一个文件中只能将同一个头文件包含一次。记住这个规则很容易,但很可能在不知情的情况下包含多次。有一种标准的C++技术可以避免多次包含同一个头文件。它是基于预处理器的编译指令#ifndef的。下面的代码意味着仅当以前没有使用预处理器编译指令#define定义的COOR_DIN_H_时,才处理#ifndef和#endif之间的语句:

#ifndef COORDIN_H_//用于对该名称的定义
#define COORDIN_H_
...
#endif

 

文件首次遇到该文件时,名称COORDIN_H_没有定义(我们根据include文件名来选择名称,并加上一些下划线,创建一个在其他地方不太可能定义的名称。若在同一个文件中遇到其他包含coordin.h的代码,编译器将知道COORDIN_H_被定义,从而跳到#endif后面的一行上。注意这种方法并不能防止编译器将文件包含两次,而只是让它忽略了第一次包含之外的所有内容。

6.3 存储持续性、作用域和链接性

C++使用三种不同的的方案俩存储数据,这些方案的区别在于数据保留在内存中的时间。

  • 自动存储持续性:在函数定义的中声明的变量的存储持续性为自动的。它们在程序开始执行其所属的函数或代码块是被创建,在执行完函数或代码块时,内存被释放。
  • 静态存储持续性:在函数定义外定义的变量和使用关键字static第一的变量的存储持续性都为静态。它们在程序的运行期间都存在。
  • 线程存储持续性:如果变量使用thread_local声明的,则其生命周期与所属的线程一样长。
  • 动态存储持续性:用new运算符分配的内存一直存在,直到使用delete运算符将其释放或程序的结束。这种内存的存储时序性为动态的,yoshi被称为自由存储或堆。

作用域描述了名称在文件的多大范围内可见。链接性描述了名称如何在不同的单元间共享。链接性为外部的名称可在文件间共享,链接性为内部的名称只能由一个文件中的函数共享。自动变量没有链接性。

6.4 自动存储持续性

如果在代码块中定义了变量,则该变量的存在时间和作用域将被限制在该代码块中。下面看下例子

int main()
{
  int adt=5;
  {
     cout<<"Hello\n;
     int bdt=-2;
     cout<<bdt<<' '<<adt<<endl;
   }
  ...
}


adt变量在内部代码块和外部代码块中都是可见的,而bdt仅在内部代码块中可见。

由于自动变量的数目随着函数的开始和结束而增减,因此程序必须在运行时对自动变量进行管理。常用的方法是流出一段内存,并将其视为栈。当函数被调用时,其自动变量将被加到栈中,栈顶指针指向变量后面的下一个可用的内存单元。函数结束时,栈顶指针被重置为函数被调用前的值,从而释放新变量使用的内存。下面来看一个例子加深一下理解。

1)调用前的栈

栈顶 (下一次添加在这里)
1890 (以前压入战中的值)
2929

(2)函数调用后的栈

将函数的参数压入栈中fib(18,50L);

栈顶
50L long值站4字节
18 int值站两字节
1890
2929

(3)函数开始执行后的栈

void fib(int real,long tell)

{ ... }

栈顶
50L 函数执行与栈关联
18 函数执行与栈关联
1890
2929

(4)函数结束后的栈

50L
18 栈顶回到原来位置
1890
2929

6.5 静态持续变量

和C语言一样,C++也为静态存储持续性变量提供了3中链接性:外部链接性(可在其他文件中访问)、内部链接性(只能在当前文件中访问)、和无链接性(只能在当前函数或者是代码块中访问)。由于静态变量的数目在程序的运行期间是不变的,因此程序不需要使用特殊的装置来管理他们。编译器将分配固定的内存块来存储所有的静态变量,这些变量在整个程序的运行期间都是存在的。另外,若果没有显示的初始化静态变量,编译器将把他设置为0.下面主要介绍三种静态变量:

 

int global=1000;//static duration,external linkage
static int one_file=50;//static,internal linkage
int main()
{
  ...
}

void func1(int n)
{
  static int count=0;//static duration,no linkage
  int llama=0;
  ...
}


 

所有的静态变量在整个的程序执行期间都是存在的。cout作用域为局部且没有链接性,其就像自动变量llama一样。而global和one_file则作用于整个文件,但区别在于global的链接性为外部的,可以在出本程序外的其他文件中使用它。

6.6静态持续性、外部链接性

链接性为外部的变量通常称之为外部变量,它们的存储连续性为静态的,作用于整个文件。下面我们先来看看外部变量的定义。一方面,在每个使用外部变量的文件中,都必须声明它;另一方面,C++有单定义原则,该规则指出,变量只能定义一次。为了满足这种需求,C++提供了两种变量的声明。一种是定义声明或简称定义,它给变量分配存储空间;另一种是引用声明或简称声明。

引用声明使用关键字extern,且不进行初始化;否则声明为定义,导致分配存储空间。如果要在多个文件中使用外部变量,只需在一个文件中包含该文件的定义,但在使用该变量的其他文件中,都必须使用关键字extern声明他:

flie1.cpp
#include"mystuff.h"
//defining an external variableint 
var=0;
void promise();

int main()
{  ...}

这个文件定义了变量var,使得编译器为他分配空间。这是我们要在另一个文件中使用它,则要使用extern关键字

file2.cpp
#include"mystuff.h"

extern var;
int main()//这里需要注意的是我的文件2并不需要包含文件1就可直接利用extern来访问外部变量
{ 
  ...
}

6.6静态持续性、内部链接性

将static限定符用于作用域为整个变量时,该变量的链接性将为内部的。如果要在其他文件中使用相同的名称来表示其他变量,该如何办呢?比如

//file 1
int errors=20;

int main()
{  ...                }

-----------------------------------
//file 2
int errors=5;
int main()
{  ...             }

---------------------------------
//file 3
static int errors=5

int main()
{  ...                   }

文件1的作法实不可取的,因为它违反了但定义的原则,但是文件3却是可取的。这并没有违反单定义原则,因为关键字static指出标示符errors的链接性为内部的。因此并没有提供外部编译。

6.7 说明符和限定符

有些被称为存储说明符或c-v限定符的C++关键字提供了其他有关存储的信息。下面是存储说明符

  • auto;
  • register;
  • extern;
  • thread_local;
  • mutable;

下面来简要的介绍一下上面的概念:

(1)cv限定符

  • const;
  • volatile;

cv表示const和volatile。最常用的的为const,在之前的介绍中一大概讲解了它。下面主要介绍volatile。该关键字的作用是为了改善编译器的优化能力。比如,假设编译器发现,程序在几条语句中两次使用了某个变量,则编译器可能不是让程序查找这个值两次,而是将这个值缓存到寄存器中。如果不讲变量声明为volatile,则编译器将进行这种优化;否则将不要进行这种优化。

(2)mutable

可以用它来指出,即使结构或类变量为const,它的某个成员也是可以被修改的

struct data
{
  char name[30];
  mutable int access;
  ...
}


 

此时我有如下代码,则是允许的

const data veep={"aaaa",0,...};
strcpy(veep.name,"cccc"};//not allowed
veep.access++;//allowed

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值