第二章
1
char
是为机器字节服务的。
wchar_t
、char16_t
、char32_t
用于确保可以存放机器最大扩展字符集中的任意一个字符。
类型char16_t
和char32_t
为Unicode
字符集服务。
2
整型:布尔、扩展字符型、(带符号)整型。
字符型被分成了三种:char
,signed char
,unsigned char
类型char
只会表现成后面两个中的一个,具体要根据编译器,表示范围分别为-128~127
,0~255
3
float
有
7
7
7个有效位,double
有
16
16
16个有效位。
4
[1]
当我们把一个浮点数赋给整数类型时,进行了近似处理; 结果值将仅仅保留浮点数中小数点之前的部分。
[2]
当我们赋给无符号类型一个超过其范围的值,结果是初始值对无符号能表示总数的取模。
当我们赋给有符号类型一个超过其范围的值,结果是未定义的。
[3]
int
和unsigned int
在同一表达式,int
会转换成无符号整数。
5
字面值常量一望而知,字面值常量的形式和值决定了它的数据类型。
0
表示八进制数,0x或0X
表示十六进制数。
short
没有对应的字面值,负数中的负号并不在字面值中。
浮点数字面值有:
3.14
,3.14E0
,0.
,0e0
,.001
并且默认是double
单引号的是char
型字面值,双引号括起来的
0
0
0 或多个字符则是字符串型字面值。
字符串字面值可以分多行书写:
int main(){
cout<<"abc"
"cde" <<endl;
}
6
普通转义序列:
泛化转义序列:
如果\
后面跟了
3
3
3个以上,只有前
3
3
3个构成转义。
然而\x
会用到所有。
7
指定字面值的类型:
L'a'
,宽字符型字面值
u8"hi!"
,utf-8
字符串字面值
1E-3F
,单精度浮点型字面值
3.14L
,扩展精度浮点型字面值
注:f
只能用在小数,不能用在整数。
8
初始化不是赋值。
列表初始化:
int a=0;
int b={0};
int c{0};
int c(0);
也可以用来赋值,但是必须加等号。
注:
{
}
\{\}
{}初始化的时候,如果会丢失信息的话,会报错(
d
o
u
b
l
e
double
double转换成
i
n
t
int
int)
9
定义于函数体内内置类型的对象如果没有初始化,则其值未定义。
类的对象如果没有显式地初始化,其值由类确定。
10
变量声明规定了变量的类型和名字,而定义申请了存储空间、可能会赋初值。
如果想声明一个变量而非定义,需要加extern int
变量的定义只能存在一个文件,其他用到该变量的文件必须声明,不能重复定义。
11
如果既有全局变量又有局部变量。
全局作用域::x
;局部作用域x
;
12
复合类型:指针和引用。
[1]
引用一般指的是左值引用,int &a=b
引用必须被初始化,并且用变量。
无法令引用转移绑定对象。
引用本身只是变量的别名,并不是对象。
[2]
指针的类型要和它指向的对象严格匹配。
把int
直接赋给指针是错误的,如果指针为空则赋为nullptr
或NULL
,后者已经不常用了。
void
指针,可用于存放任意对象的地址,但是我们不知道对该地址中到底是个什么类型。
不能对其进行访问。
13
声明
=
=
=基本数据类型+声明符。
类型修饰符:unsigned
、signed
、short
、long
、&
、*
。
int* p1,p2;
仍然只有p1
是指向int
的指针。
一般只有两种写法:
int *p1,*p2;int* p3;
该部分为复合类型的声明。
14
int *p0=&p;int **p1=&p0;
**
为指向指针的指针。
引用不是对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用。
int i = 32;
int *p;
int *&r = p;
r=&i;
*r=0;
注:
∗
*
∗优先级高于
&
\&
&,并且此处&*r
会报错,提示是将指针声明成int &
。
15
const
对象必须初始化。
const int i = get_size()
运行时初始化。
const int i = 0;
编译时初始化。
const
默认作用域在本文件,如果要多个文件使用,则需要定义:
extern const int bufsize = getsize()
16
对常量的引用为:const int&
,非常量引用不能指向一个常量对象。
[1] 如果你对常用的引用绑定了一个非常量的话,你不能通过该引用修改,但是原非常量可以修改,最后通过该引用访问的结果可以不同。
[2] 如果要先转换成同一类型,编译器隐式转换成了一个临时量,所以对常用的引用绑定到了一个临时量上,这显然是无意义的。
int main(){
int sz=0;
const int &x=sz*2;
sz=1;
cout<<x<<endl;
}
输出的
x
x
x还是
0
0
0。
[3] 指向常量的指针是const int *p
,指针可以多次赋值,但是不能修改。
[4] 引用不是对象,但指针是,所以指针是可以修改的,所以有常量指针的概念。
常量指针:int *const x
指向常量的常量指针:const double *const pip = &p;
P
S
:
PS:
PS:依旧是从右往左读来以便理解。
16
const int &p = 0;
右边是字面值常量的时候,左边引用必须是常量。
x=0.0;const int &p = x;
显然也是要常量的,因为类型转换的时候产生了临时量,实际绑定的时候临时量。
const int *p=&x;int *q=p;
是错的,指向常量的指针不能赋值给普通指针。
[因为这样就不能保证指向的对象受到保护,不会被修改]
17
顶层const
表示指针本身是个常量。
底层const
表示指针指向了常量。
赋值的时候,如果右值是顶层const
显然无影响。
但是如果是底层const
,那么右边是指向一个常量对象的,左边不能是int
,否则默认为给予了修改的资格(编译器是不允许的)。
18
常量表达式指的是值不会改变且在编译过程就能得到计算结果。
显然字面值就是常量表达式,用常量表达式初始化的const
对象也是常量表达式。
const int x=1;
是
int y=28;
不是
所以无法判断是否是常量表达式,还是运行时得到的结果。
constepxr
用编译器验证是否是常量表达式。
constepxr int x=1;
这样就可以保证不会出现运行时确认了(运行结果有误)。
19
算数类型、指针、引用属于字面值,String
等不属于。
constexpr
用到的类型称为字面值类型,同时constexpr
也相当于顶层的const
,即其实是常量对象,而不是指向常量的(指针)
constexpr const int *p=&i
顶层+底层const
20
typedef double wages;
typedef wages base,*p;
p
是double*
的同义词。
别名声明using SI=Sales_item;
对于typedef char *pstring
,const pstring cstr = 0;
指的是指向char
的常量指针。
因为pstring
是指向char
的指针,const
修饰的是pstring
,也就是指针。
这里是不能直接改写成const char *cstr
的。
21
atuo
会保留底层const
,忽略顶层const
const auto
可以使得推断出来的类型不会忽略顶层const
。
可以将引用的类型设为auto
字面值只能绑定在常量引用上。
并且在引用的时候,atuo
不会忽略对应的顶层const
,不过此时的const
本身也是底层了。
当同一行auto
推断类型不一样会报错,例如const int
和int
:
const int i = 0;
auto j2=i,&k2=i;
是不正确的,左边是int
,右边由于不是顶层const
所以并没有忽略const
,引用是cosnt int
。
22
decltype(x)
可以获取x
的类型,可用于声明:
int x;
decltype(x) y=1;
等价于
int y=1;
甚至于我们可以获取引用的类型
23
如果r
是引用的话:
decltype(r)
是引用类型,decltype(r+0)
则是r
所指向的内容
decltype(*p)
因为*p
可以赋值,也是指向了对象,所以等于int&
decltype((p))
,带了括号所以会认为其是表达式,并且还能赋值,所以结果是引用。
24
头文件保护符:
预处理变量:define
ifdef
当且仅当变量已定义
ifndef
当且仅当变量未定义
endif
直到结束
预处理变量无视作用域的规则。