Primer 变量与基本数据类型

基本内置类型

含无符号类型的表达式

隐式类型转换顺序:

如果表达式中既有带符号类型和无符号类型,带符号数会自动转换为无符号类型;

字面值常量

'a':字符字面值,hi:字符串字面值

20十进制,024八进制,0xff十六进制,\x4d\77均表示M

指定常量的类型:

前缀 含义 类型
u unicode16字符 char16_t
U unicode32字符 char32_t
L 宽字符 wchar_t
u8 utf-8 char
整形字面值 浮点型字面值 "
后缀 最小匹配类型 后缀 类型
u,U unsigned f,F float
l,L long l,L long double
ll,LL long long

L'a' //宽字符型 u8"hi!" //utf-8 1E-3F //float 3.14 //long double

变量

列表初始化

使用花括号来初始化成为列表初始化;

1
2
3
4
int a = 0;
int a = {0}; //下面三个为列表初始化
int a{0};
int a(0);

如果使用列表初始化且初始值存在丢失信息的风险,则编译器会报错;但是,使用普通的列表初始化并不会出错;

1
2
3
double a = 3.14;
int b = a; //正确
int b = {} //错误

分离式编译

C++语言允许分离式编译,该机制允许将程序分割为若干个文件每个文件可被独立编译;

声明与定义

1
2
3
extern int i;   //声明i而非定义
int i; //声明并定义
extern int i = 10;//定义

extern语句若包含初始值也就变成了定义

引用

引用必须被初始化,int &a是错误的,定义引用时,程序把引用和它的初始值一直绑定在一起,一旦初始化完成,引用和它的初始化值对象一直绑定在一起,;因为无法令引用重新绑定到另外一个对象,因此引用必须初始化;

引用本身不是一个对象,因此不能定义引用的引用;

1
2
3
int &val1 = 10; //错误,引用类型的初始值必须是一个对象,这个非常关键
double val2 = 3.14;
int &val3 = val2; //错误,类型不匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
using namespace std;

int main() {
int a = 027;
int c = 10;
int &b = a;
cout << a << " " << b << endl;
// 23 23
b = c;
cout << a << " " << b << endl;
// 10 10
}

int *& 与int &*

从内往外看,int *&定义的是指针的引用,int &*定义的是引用的指针,而引用又不是对象,因此没有指针;所以第二种写法严格来说是错误的;

void *

void *是一种特殊的指针类型,可用于存放任何对象的地址,因此对于它的地址中存放着一个什么类型的对象是不知道的;

并且以void *视角访问内存,只能访问到地址,而不能访问到具体地址的对象;

令注:在c++/c中进行指针类型转换不是一件随便的事情

1
2
3
4
int i = 10;
// 下面这条语句是非法的
//long *lp = (long *)&i
long *lp = &i;

const

const对象必须进行初始化;

1
2
//这条语句是错误的
const int k;

const类型的对象只能执行不改变其内容的操作;如算数运算,转换成一个布尔值;

const与初始化

如果用一个对象去初始化另一个对象,则它们是不是const都无所谓;

1
2
3
4
int i = 42;
// 下面两条语句都是合法的
const int ci = i; // 拷贝
int j = i; // 拷贝

ciconst特征仅仅在执行修改它的操作时才发挥作用;

const的引用

可以把引用绑定到const上;对const的引用常称为“常量引用”;

1
2
3
4
const int ci = 1024;
const int &r1 = ci;
r1 = 42; // r1 是对常量的引用,不能修改,错误
int &r2 = ci // 非常量引用绑定常量上,错误

虽然非常量引用不允许绑定到常量上,但是常量引用允许绑定到非常量上

初始化与对 const 的引用

1
2
double dval = 3.14;
const int &ri = dval;

上面两条语句其实本质是这样的:

1
2
3
double dval = 3.14;
const int temp = dval;
const int &ri = temp;

下面两条语句是错误的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const int &ri = 10;
int &r = r1 * 2; //非常量引用不允许绑定到常量上

// 下面两条语句也是错的
int a = 10;
int &b = a * 2;

//本质上:
int a = 10;
const int temp = a * 2;
int &b = temp; //非常量引用显然不允许绑定到常量上,因此错误

//这两条语句是对的
int c = 10;
int &d = c;

非 const 与 const 引用同时绑定

1
2
3
4
5
int i = 42;
int &r1 = i;
const int &r2 = i;
r1 = 0; // 正确
r2 = 0; // 错误

const 与指针

与引用相似,要存放一个 const 类型变量的地址,只能用指向 const 类型变量的指针;但是指向常量的指针没有规定其所指对象必须是常量;

1
2
3
4
int num = 0;
int *cosnt p1 = &num; //p1 只能指向 num,不能改变
const double pi = 3.14;
const int *p2 = &pi; // p2指向一个常量

constexpr

声明为 constexpr 的变量一定是一个常量,而且必须用常量表达式初始化;

1
2
3
constexpr int mf = 20;  // 20 是常量表达式
constexpr int limit = mf + 1; // mf + 1 是常量表达式
constexpr int sz = size(); // 只有size()是 constexpr 函数时,才是正确的语句,即使size()返回值是 常数也不行;

对于 constexpr 的声明中,它仅对指针有效,对指针所指对象无关;

null与nullptr

首先需要明确, null 是无类型的,而 nullptrnullptr_t 类型的;

在c++中不能将void *类型转换成其他类型,在c++中,在stddef.h中null是这样定义的:

1
2
3
4
5
6
#undef NULL
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif