第二章 变量与基本类型

2.1基本内置类型

  • C++定义了 包括算术类型空类型(void)
  • 算术类型包含了 字符 整型数 布尔值和浮点数 分为两种类型 整型(包括字符和浮点型)和浮点型。
  • 算术类型在不同机器中尺寸有所区别(类型数据所占比特的最小值)
  • 函数不返回任何值时使用空类型作为返回类型
C++ 算数类型
类型含义最小尺寸
bool布尔类型未定义
char字符8位
wchar_t宽字符16位
char16_tUnicode字符16位
char32_tUnicode字符32位
short短整型16位
int整形16位
long长整型32位
long long(C++11新定义)长整型64位
float单精度浮点数6位有效数字
double双精度浮点数10位有效数字
long double扩展双精度浮点数10位有效数字
  • 一个long类型至少和int类型一样大 一个longlong至少和long一样大

内置类型的机器实现

  • 可寻址基本内存块为字节(type) 存储的基本单元为字(有几个字节构成)
  • 大多数机器字节由8比特构成 字由32位/64位构成也就是4/9字节
  • 类型决定数据所占比特数以及如何解释比特内容

带符号类型和无符号类型

  • 出去布尔和扩展的字符型外分为 有符号类型(signed)和无符号类型(unsigned) 带符号类型表示 正数 负数和0 无符号类型仅能表示大于等于0的值
  • 字符型分为三种 char、signed char、unsigned char 表现形式只有两种 无符号和有符号
    具体使用哪种类型由编译器决定

如何选择类型

  • 明确数值不为负数时使用 unsigned
  • 使用 int 进行整型运算 short太小 long一般于int大小一致 超出取值范围时使用longlong
  • 算数表达式尽量不要使用char和bool 只有存放时使用 char在一些机器上具有符号在另一些又不具备符号 如果使用不大的整数指明他的类型时 signed char或者unsigned char(需要探究 不理解)?
  • 执行浮点运算时使用double,float与double计算代价几乎一致 通常情况下单精度不够
    long double 一般没有必要 不要考虑运行消耗

2.1.2类型消耗

  • 对象的类型定义对象包含的数据以及能参与的运算
  • 赋值给无符号类型一个超出表示范围的值时 结果是初始值对无符号类型表示数值总数取模后的余数 8比特大小的unsigned char 表示0-255区间的值 实际结果时 该值对256取模后的余数 -1赋给该类型得到结果为 255
  • 避免做出无法预知和依赖于环境的操作 比如int尺寸取值 不同机器不同 结果不同
  • 算术中出现无符号又含有int值时 int值会转换成无符号数 int转换为无符号一样

2.1.3字面值常量

  • 类似-42的表达式 字面值常量为42 负号不在字面值常量内作用仅仅为字面值取负值
  • 字符串常量比实际内容多1 编译器在每个字符串结尾添加‘\0’
转义序列字符转义序列字符
换行符\n横向制表符\t
纵向制表符\v退格符\b
反斜线\\问号\?
回车符\r进纸符\f
报警符\a双引号\"
单引号\’
  • 八进制反斜线后面最多跟3位数字 十六进制则用到\x后所有数字

复习一下两组定义是否有区别

int month = 9,day = 7;
int month = 09,day = 07;

2.2.2变量声明与定义

  • 声明规定变量的类型和名字(定义与之相同???) 使变量被程序所知
  • 定义负责创建与声明相关实体 申请存储空间也可能赋初值
extern int i; //声明 i 而不定义 i
int i; //声明并定义 i
  • 任何包含显式初始化的声明为定义 extern 如果被初始化则失去作用
  • 变量能且只能被定义一次 但是可以多次声明
  • 定义开辟存储空间 变量一但被定义就不能被再次定义 只能多次声明
  • C++是一种静态类型语言 在编译阶段检查类型

2.2.3标识符

2.2.4名字的作用域

  • 全局作用域 块作用域

  • 内层作用域 外层作用域

2.3复合类型

  • 复合类型是指 基于其他类型定义的类型

  • 引用和指针

引用

  • 定义引用时程序把引用和对象绑定(bind)到一起 一旦初始化完成将一直绑定在此对象上 无法重新绑定 因此必须初始化

  • 引用本身不是对象 因此不能定义引用的引用 引用的类型必须与引用对象的类型相同 两种例外(在初始化常量引用时可以使用任意表达式作为初始值 只要能符合类型转换)

  • 引用本质上是一个常量指针 编译过程使用常量指针 作为引用内部实现 因此引用所占用的空间大小与指针相同

  • Type& name; <-->Type* const Name 
    

指针

  • 指针本身是一个对象 允许对自身赋值以及拷贝 因此类型可为 指针的指针

  • 指针未初始化将得到不确定的值 空为nullptr(C++11)nullptr是一个特殊类型的字面值 可转换为任意指针类型

  • 指针值

    • 指向一个对象

    • 指向紧邻空间的下一个位置

    • 空指针

    • 无效值

  • 使用未初始化指针 指针所占存储空间的内容将被看作为地址 若恰好有值 无法辨别是否非法

  • & * 在类型后面 为声明的一部分 表明变量为 引用/指针

  • 在表达式中 为取地址符 解引用符

2.3.3复合类型的声明

  • int *p数据类型为 int型 *只用来修饰p int* p,q; p为int类型的指针,q为int类型变量。

  • 引用不是对象 不能定义指向引用的指针

  • int i=3;
    int *p=;
    int *&r=p; ///r是指向指针的引用
    r=&i; //r表示指针p 此处将i的地址赋予p 
    *r=0;//解引用得到i(P所指向的对象)
    

练习 说明下面变量的类型和值

int* ip,i,&r=i;
int i,*ip=0;
int* ip,ip2;

2.4const限定符

  • 默认状态下 const只在文件内有效 多个文件出现相同命名const 为不同变量

  • const在编译下替换变量为值 const int asd=5; 将asd替换为5

  • 在不同文件使用相同定义const 使用extern

  • const double i=3.14;
    const int &r=i;//此操作下 生成临时量对象 const int temp=i; 引用r绑定的对象是临时对象temp C++规定此类操作非法
    
  • const引用可以引用非const变量 不能通过const引用改变值

2.4.2 const与指针

  • 指向常量的指针只能为 const const对象不允许改变值 而非常量指针获取对象地址时有可能改变值
  • 指向常量的指针 允许指向非常量 只是不能通过该指针改变对象值
  • 常量指针 int * const 指向常量的常量指针 const int * const 常量指针必须初始化

2.4.3顶层const

  • 顶层const表明 指针为一个常量 底层const表明 指针指向一个常量

  • 执行拷贝操作对象底层const具备相同资格(不指向const 或都指向const)或 能进行类型转换

2.4.4constexpr和常量表达式

  • 常量表达式指 值不会改变在编译过程中就能得到计算结果的表达式
  • 字面值属于常量表达式
  • 对象或表达式 是不是常量表达式 由类型和初始值共同决定
  • 声明为constexpr 必定为常量
  • constexpr(C++11) 使用此关键字 交由编译器验证是否为常量表达式

2.5类型处理

typedef char *pstring;  //pstring为指向char的指针
pstring *p;   //p为指向char的指针的指针
const pstring A=0;//const修饰pstring pstring为指向char的指针  A为指向char的常量指针
//注意不要单纯以替换类型推断

2.5.2 auto类型说明符

  • auto(c++11新引入) 由编辑器推断值 必须初始化
void 自动类型与Const()
{
    const int i = 42;
    int a = 40;
    auto j = i;
    const auto &k = i;
    auto *p = &i;
    const auto j2 = i, &k2 = i;
    auto e = &i;
    int &r = a;
    decltype(r) s = a;
    cout << typeid(r).name() << endl;
    cout << typeid(e).name() << endl;
    cout << typeid(p).name() << endl;
    cout << typeid(j).name() << endl;
    cout << typeid(j2).name() << endl;
    cout << typeid(k2).name() << endl;
    cout << typeid(s).name() << endl;
}

2.5.3 decltype类型符

  • 推断表达式类型而不实际执行表达式 decltype(c++11)
 	const int ci = 0, &cj = 0;
    decltype(ci) x = 0;			//x为 const int
    decltype(cj) y = x;			//x为 const int&
    //decltype(cj) z; z为引用
    
    int i = 0, &r = i, *p = &i;
    decltype(r) s = i;			//r为引用 s为int&
    decltype(r + 0) d;			// r+0 表达式结果为int d为int
    //decltype(*p) v; v为int& 必须初始化 
    
    //如果时加了括号的变量 返回引用
    decltype((i)) z = i;		//i为int&
    decltype(i) c;				//c为int类型

  • 如果表达式时解引用操作 将得到引用类型 解引用指针能得到指针所指的对象
  • 对于decltype所用表达式来说,如果变量名加上一个括号,则得到的类型与不加括号时有不同,不加括号的到变量的类型,加上一层或多层编译器会将此当作表达式。**变量时一种作为赋值语句左值的特殊表达式,所以decltype得到引用类型 **

2.6自定义数据结构

  • c++11新标准规定 可以为数据成员提供一个类内初始值,创建对象是类内初始值用于初始化成员,没有初始值的成员将被默认初始化

预处理

  • 预处理之一 #include 编译器遇到此标记 使用制定头文件代替
  • 预处理: 头文件保护符 头文件保护符依赖于预处理变量
  • 预处理变量由两种状态 已定义 未定义
  • #define将一个名字设置为预处理变量另外两个指令检查是否被定义
  • #ifdef 当且仅当变量已定义为真 #ifnedf 当且仅当变量未定义为真
  • 检查结果为真,则执行后续操作直到遇到 #endif
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值