C++ Primer 5th 阅读笔记:变量和基本类型
一些语言的公共特性
- 内建类型,如整型,字符型等;
- 变量,为值绑定的一个名字;
- 表达式和语句,操作值。
- 分支和循环,允许我们条件执行和重复执行;
- 函数,定义抽象计算单元。
扩展语言的方式
- 自定义类型;
- 标准库。
本章重点
学习语言的基本知识和标准库。
- 内建类型;
- 简要介绍自定义类。
类型
- 定义了数据的意义;
- 定义了数据的操作;
从二进制的角度看,类型定义了数据占用几个 bit
,以及如何解释这些 bit
。
基本内建类型
- 算术类型
- 整型
- 字符型
- 布尔型
- 浮点型
- 特殊类型:void
算术类型
- 整型 (integral types)
bool
: 两个值true
,false
。char
:可以包含basic character set
中的字符对应的数字。大小等于一个机器字节(single machine byte)。wchar_t
,char16_t
,char32_t
。用于extended character sets
。
wchar_t
可以包含最大extended character sets
中字符对应的数字。(Windows 2 字节;Unix 4 字节)
char16_t
,char32_t
用于 Unicode 字符。
有关
char
的进一步讨论,见 Byte是8位吗?—C语境中的Byte及C语言的char类型
- 浮点型 (floating-point types)
标准没有定义具体的数据格式。一般使用的都是 IEEE 格式。
关于浮点数的详细介绍可见:IEEE 754浮点数标准详解
符号
- 有符号:
signed int/int
,signed short/short
,signed long/long
,signed long long/long long
,signed char
。
标准没有定义具体的数据格式。一般为补码。 - 无符号:
unsigned int/unsigned
,unsigned short
,unsigned long
,unsigned long long
,unsigned char
。 - 特殊:
char
有无符号看编译器的实现。
算术类型的经验法则
- 不包含负数,使用无符号数。
- 使用
int
来进行整数运算。short
太小,long
一般和int
一样大。如果数字太大使用long long
。 - 不要在算术运算中使用
char
和bool
。可以在算术运算中使用signed char
和unsigned char
。 - 浮点数运算使用
double
。float
精度有限且带来执行效率上的提升不大。long double
的计算开销过大,一般不使用。
类型转换
赋值语句
- 左值类型:
bool
右值类型:非bool
转换规则:0
->false
,≠0
->true
- 左值类型:非
bool
右值类型:bool
转换规则:false
->0
,true
->1
- 左值类型:整型
右值类型:浮点型
转换规则:f
->int(f)
- 左值类型:浮点型
右值类型:整型
转换规则:z
->z.00
- 左值类型:无符号数
- 右值类型:超出范围的数
转换规则:n
->n % N
;n
是超出范围的数,N
是无符号类型能表示的所有值的个数
表达式
如果在算数表达式中同时出现 有符号数
和 无符号数
,所有 有符号数
转换为 无符号数
。
一例无限循环的错误代码,
// WRONG: u can never be less than 0; the condition will always succeed
for (unsigned u = 10; u >= 0; --u)
std::cout << u << std::endl
有关
有符号数
和无符号数
的一些资料:
未定义的行为和实现定义的行为
避免未定义的行为(undefined behavior)和实现定义的行为(implementation-defined behavior)。使用这些行为可能造成程序不可移植(nonportable)。
建议参考以下的文章:
字面量
整型
整数 20
的三种表示法
- 十进制:
20
- 八进制:
024
,0
开头 - 十六进制:
0x14
,0x
开头
十进制字面量默认都是 有符号数
。
八进制和十六进制则可以为 有符号数
或者 无符号数
。
十进制字面量的类型为 int
,long
,long long
中可以容纳字面量值的最小类型。
八进制和十六进制的类型为 int
,unsigned int
,long
,unsigned long
,long long
,unsigned long long
中可以容纳字面量值的最小类型。
如果最大类型也不能容纳字面量,则将引起一个错误。
注意:
-42
不是字面量,42
才是字面量,-
在其中作为相反数的操作符。
浮点型
浮点数的字面量包含了小数点或者指数(使用科学计数法)。指数使用 e
或者 E
来表示。
3.14159
3.14159E0
0.
0e0.001
科学记数法的形式是由两个数的乘积组成,aEb
= a×10^b
。
浮点型字面量的默认类型是 double
。
字符和字符串字面量
- 字符字面量,包含在单引号中的一个字符
'a'
; - 字符串字面量,包含在双引号中的 0 个或多个字符
"abcd"
。
字符串字面量是一个字符数组,每个字符串字面量的最后都会有一个 零字符 '\0'
(null character)。
多个相邻的字符串字面量会被自动拼接成一个字符串字面量,比如,
// multiline string literal
std::cout << "a really, really long string literal "
"that spans two lines" << std::endl;
转义序列
转义序列用于表示 非打印字符
或者有特殊含义的字符(如,单引号、双引号)。
转义序列使用 \
开头。
一般化的转义序列:
\
后面跟 1 到 3 个八进制数字(0-7
);\x
后面跟 1 或者多个十六进制数字(0-f
)。
注意:
- 如果 \ 后面跟了四个及以上的八进制数,只有前三个字符会被解释成一般化的转义序列;
- 如果 \x 后面跟了多个十六进制数,十六进制数会用尽所有的数来表示一个字符。
参考资料:
字面量类型
我们可以通过添加前缀(针对字符字面量或者字符串字面量)或者后缀(针对整型字面量或者浮点数字面量)的方式来修改默认的字面量类型。
最佳实践:在使用
L
作为后缀时,建议使用大写L
, 而不要使用小写l
,目的是为了区分字母l
和数字1
。
注意:后缀只是指定了字面量能接受的最小类型,如果字面量的值无法被容纳在这个最小类型内,字面量将会尝试下一个更大的类型。
其他字面量
bool
字面量:true
和false
;- 指针字面量:
nullptr
。
参考资料:
变量和对象的区别
在本书中的变量和对象没有区别!
变量定义
- 变量类型指示符(type specifier)
- 一个或者多个变量名(使用逗号隔开)
2.1. 可以为变量指定一个初始值(可选) - 分号
;
结束
示例:
int sum = 0, value, units_sold = 0;
Sales_item item;
std::string book("0-201-78345-X");
初始化
- 可以使用之前定的变量来进行初始化;
- 初始化和赋值在 C++ 中是两个不同的操作;
示例:
double price = 109.99, discount = price * 0.16;
double salePrice = applyDiscount(price, discount);
关于初始化与赋值的区别,可以查看 CSDN 初始化与赋值的区别
对于基本数据类型,二者是没有任何区别,对于非基本数据类型,在写法与效率上有许多不同。
列表初始化
四种初始化的方式:
int units_sold = 0;
int units_sold = {0};
int units_sold{0};
int units_sold(0);
C++11 中使用花括号来初始化内建类型,如果存在类型转换且具有数据丢失的风险,则编译器将会报错。
long double ld = 3.1415926536;
int a{ld}, b = {ld}; // error: narrowing conversion required
int c(ld), d = ld; // ok: but value will be truncated
关于花括号初始化的更多内容,可以参考: C++11 花括号初始化
关于 initializer 的解释,可以参考 Initializers
默认初始化
变量的初始化取决于:
- 变量的类型
- 变量定义的位置
内建类型:
- 定义在函数外的变量会被初始化为 0
- 定义在函数内的变量不会被初始化(uninitialized)
变量声明(Declaration)和变量定义(Definition)
声明
变量声明指定了变量的类型和名称。
定义
变量定义也是变量声明。
变量定义指定了变量的类型和名称。
变量定义分配存储空间。
变量定义可以指定一个初始值(可选)。
如何声明一个变量?
- 添加
extern
关键字; - 不要提供初始值。
extern int i; // declares but does not define i
int j; // declares and defines j
任何包含初始值的声明都是定义。
extern double pi = 3.1416; // definition
注意:变量可以被声明多次,但只能被定义一次。
关于声明和定义的参考资料
标识符
- 由字母、数字、下划线组成;
- 无长度限制;
- 大小写敏感;
语言保留字
标准库保留字
- 不能出现两个连续的下划线,如
__i
; - 不能下划线之后跟着大写字母,如
_I
; - 函数外的标识符,不能以下划线开头,如:
int _i; // WARNING: DISALLOW!
int main()
{
...
}
关于保留字的参考资料:
命名习惯
- 名称应符合它的用法;
- 变量一般是小写字母,如
index
; - 类名称通常以大写字母开头,如
Sales_item
; - 名字多个单词之间需要加以区分,
- 下划线命名:
student_loan
- 驼峰式命名:
studentLoan
- 下划线命名:
关于命名法的参考资料
作用域(Scopes)
每个名称都有自己关联的实体,比如,变量、函数、类型等等。
每个名称都对应的作用域。
作用域一般使用花括号来界定。
相同的名称在不同的作用域中可以关联不同的实体。
名称的可见性从声明的地方开始,直到声明所在作用域的结尾结束。
分类
- 全局作用域(global scope):在整个程序可见
- 块作用域(block scope)(局部作用域):仅局部可见
建议:尽量在靠近变量第一次使用的地方定义变量。
嵌套作用域(Nested Scopes)
一个作用域可以包含其他作用域。
外部作用域(Outer Scope) 包含了内部作用域(Inner Scope)。
外部作用域中的名字可以被其内部作用域使用。
外部作用域中的名字可以被其内容作用域重新定义。
作用域操作符(::
)
如果 ::
左侧为空,其代表全局作用域。
我们可以通过作用域操作符来忽视默认的域规则。
复合类型
复合类型是根据另一种类型定义的类型。
复合类型包括:
- 引用;
- 指针;
- 等等。
声明语句是一个基本数据类型(base type) 跟着一组声明符(declarators)。
声明符,一是给了变量的名称,二是给了变量的类型(基于基本数据类型)。
引用
引用定义了变量的一个别名。
引用的声明符格式为: &var
。
引用的必须初始化。
引用不可修改。
引用的类型和被引用对象的类型必须匹配(但存在例外)。
引用只能用变量初始化,不能用字面量或者符合表达式。
指针
指针用于间接访问其他元素。
指针本身就是对象。
指针可修改。
指针定义可以不初始化。
指针的声明符格式为: *var
。
指针存储了另一个对象的地址。
我们通过取址符&
(address-of operator) 来获取对象的地址。
指针的类型和被指向对象的类型必须匹配(但存在例外)。
四种状态
- 指向一个对象;
- 指向对象的后面一个位置;
- 空指针,不指向任何对象;
- 无效指针。
使用解引用操作符 *
来访问指向的对象。
空指针
空指针不指向任何对象。
空指针的三种表示:
- 字面量
0
- 宏定义
NULL
- 字面量
nullptr
(推荐使用)
注意:不能将一个整型变量赋值给指针,即使整型变量的值为
0
。
为什么指针难以调试?
- 指针的值代表一个地址,我们很难区分合法的地址和非法的地址。
- 建议:初始化所有指针,指向一个具体的对象,或者空指针。
- 建议:只在被指向的对象定义后,再定义指针。
指针转换到布尔值:
- 空指针转换为
false
; - 其他指针转换为
true
。
void*
指针
void*
指针可以指向任意一个对象。
void*
指针不保存指向对象的类型信息。
我们无法通过 void*
指针操作其指向的对象。
参考资料:
复合类型的声明
定义语句是一个基本数据类型(base type) 跟着一组声明符(declarators)。
一个定义中可以定义不同类型的变量。
// i is an int; p is a pointer to int; r is a reference to int
int i = 1024, *p = &i, &r = i;
类型修饰符(type modifier) 仅应用于单个标识符。
定义多个变量的两种风格:
- 类型修饰符和标识符相邻;
int *p1, *p2; // both p1 and p2 are pointers to int
- 基本数据类型和类型修饰符相邻。
int* p1; // p1 is a pointer to int
int* p2; // p2 is a pointer to int
const
限定符(qualifier)
const
修饰的变量无法被修改。
const
的默认作用域为本文件。因为 C++ 是单独编译每个文件的,我们要将 const
替换为具体的值,需要知道它的定义,所以每一个文件中都包含了 const
的定义,但是不会导致重复定义的情况出现。
如果我们想要在多个文件中共享 const
变量,但是其初始值不是常量表达式(无法在编译阶段获取表达式的值):
- 在一个文件中声明
const
变量,需要extern
关键字 - 在一个文件中定义
const
变量,需要extern
关键字。
// file_1.cc defines and initializes a const that is accessible to other files
extern const int bufSize = fcn();
// file_1.h
extern const int bufSize; // same bufSizeas defined in file_1.cc
const
的引用无法修改引用的对象。
const
的引用的初始值可以为,
- 常量对象;
- 非常量对象;
- 字面量;
- 一般表达式(类型可以不匹配)。
只要初始值可以转换为引用的类型。
double dval = 3.14;
const int &ri = dval;
等价于
double dval = 3.14;
const int temp = dval; // create a temporary const int from the double
const int &ri = temp; // bind ri to that temporary
const
的指针无法修改指向的对象。
const
的指针可以指向非 const
的对象。
const
指针:指针本身无法被修改。
const
指针:必须被初始化。
const
指针的声明,将 const
放在标识符前面,而不是基本数据类型前面。
顶层 const
:对象本身是 const
,对象本身能否被修改。
底层 const
:对象指向的对象是 const
,指向对象能否被修改。
对象出现在 =
右侧时,顶层 const
可以被忽略,因为顶层 const
只是阻止对象被修改,但是不阻止对象被拷贝和访问;
对象出现在 =
右侧时,底层 const
必须考虑,因为底层 const
限定了指向对象的操作权限(是否能修改),在拷贝时,只能使得权限不变或者缩小(从可修改到不可修改),反之则不行——可以从 const
到 const
或者 non-const
到 const
,但是 const
到 non-const
是不允许的。
参考资料:
constexpr
和常量表达式
常量表达式是以下几种:
- 字面量
- 使用常量表达式初始化的
const
对象 - 表达式中的所有子表达式都是常量表达式
NOTE:
const
对象不一定都是常量表达式non-const
对象一定不是常量表达式
const
语义接近 readonly
——只读变量; constexpr
的语义接近常量(可以在编译阶段就确定)。
如果你只将变量用作常量表达式,推荐加上 constexpr
关键字。
字面量类型:所有可以使用 constexpr
的类型被称为字面量类型。
字面量类型包括:
- 算数类型
- 引用类型
- 指针类型
- 其他一些
字面量类型不包括:
Sales_item
类IO
string
类型
NOTE:当 constexpr
用于指针类型的声明时,constexpr
会添加一个顶层 const
。
const int * p = nullptr; // p is a pointer to a const int
constexpr int * q = nullptr; // q is a const pointer to int
如上的两个语句有不同的语义。
复杂类型
复杂类型的两个特点:
- 复杂类型很长,写起来容易出错;
- 复杂类型可能包含很多参数,难以理解它的意义和用途。
参考资料:
C++ const 和 constexpr 的区别? - Codebowl靓仔的回答 - 知乎
constexpr对编译时间影响大吗?
类型别名
定义类型别名的两种方式
typedef
typedef double wages; // wages is a synonym for double
typedef wages base, *p; // base is a synonym for double, p for double *
typedef
中的类型声明符可以包含类型修饰符,可以用来定义复合类型的别名。using
using SI = Sales_item; // SI is a synonym for Sales_item
using SP = Sales_item*; // SP is a synonym for Sales_item*
指针类型别名和 const
混用时,别名作为一个基本数据类型出现在声明中,const
是顶层 const
,表示对象不可变。
auto
关键字,类型指定符
当我们想要通过一个变量来保存表达式的值时,如果遇到表达式值的类型过于复杂,可以使用 auto
关键字来自动推导出变量的类型。
我们可以用 auto
来定义多个变量,多个变量必须有相同的基本数据类型。
auto i = 0, * p = &i; // ok: i is int and p is a pointer to int
auto sz = 0, pi = 3.14; // error: inconsistent types for sz and pi
一些特殊规则:
- 对于引用类型,
auto
会使用引用对象的类型 - 对于顶层
const
,auto
会忽略,对象本身是否可变;如果想要推导出的类型有高层const
,必须显式地指定。const auto f = ci; // deduced type of ci is int; f has type const int
- 对于底层
const
,auto
会保留,指向对象是否可变
可以通过 auto
来定义一个引用,引用指向的对象的顶层 const
不会被忽略。
auto &g = ci; // g is a const int& that is bound to ci
auto &h = 42; // error: we can’t bind a plain reference to a literal
const auto &j = 42; // ok: we can bind a const reference to a literal
通过 auto
来定义多个变量时,如果变量包含修饰符,会改变 auto
的推导结果。
- 指针修饰符:返回表达式指向的对象的类型。顶层
const
保留。 - 引用修饰符:返回表达式的类型。顶层
const
保留。
auto k = ci, &l = i;
auto &m = ci, * p = &ci; // m is a const int&; p is a pointer to const int
auto &n = i, * p2 = &ci; // error: type deduced from i is int; type deduced from &ci is const int
decltype
关键字,类型指定符
有的时候,我们想用推导出表达式的类型,但是却不想用这个表达式来初始化变量。
decltype
返回操作对象的类型,但是不会对其进行求值。
decltype(f()) sum = x; // sum has whatever type f returns
NOTE:
decltype
返回的类型会保留顶层const
,这与auto
的有所不同。decltype
针对引用类型会返回引用类型,而不是引用类型指向的对象。decltype
解指针引用会返回引用类型。decltype((variable))
会返回引用类型。decltype
针对赋值表达式也会返回引用类型。
参考资料
c++11 decltype(*p) 得到的结果是T&的设计思路?
C++11中的decltype和declval表示什么意思,它们是如何使用的,会在什么时候使用?
What is the difference between auto and decltype(auto) when returning from a function?
The relationship between auto and decltype
C++ Primer 5th 阅读笔记:变量和基本类型的更多相关文章
- C++ primer 5th 第二章 变量和基本类型 阅读笔记
第二章 变量和基本类型 第一节 基本内置类型 C++标准规定了算术类型尺寸的最小值,同时允许编译器赋予这些类型更大的尺寸. 比如: 类型 含义 最小尺寸 bool 布尔类型 未定义 wchar_t 宽 ...
- C++ Primer 第2章 变量和基本类型
C++ Primer 第2章 变量和基本类型 C Primer 第2章 变量和基本类型 1 基本内置类型 算数类型 类型转换 字面值常量 2 变量 变量定义 3 复合类型 引用d左引用 指针d 4 c ...
- Javascript权威指南阅读笔记--第3章类型、值和变量(1)
之前一直有个想法,好好读完JS权威指南,便于自己对于JS有个较为全面的了解.毕竟本人非计算机专业出生,虽然做着相关行业的工作,但总觉得对于基础的掌握并没有相关专业学者扎实,正好因为辞职待业等原因,还是 ...
- C++ 学习笔记 变量和基本类型(一)
C++ 学习笔记 一.变量和基本类型概述 类型是所有程序的基础.类型告诉我们数据代表什么意思以及可以对数据执行哪些操作. c++基本类型: 字符型 整型 浮点型 c++ 还提供了可用于自定义数据类型的 ...
- C++ Primer : 第二章:变量和基本类型(1)
变量和基本类型之第一篇:基本内置类型和变量 一. (1) C++定义了一套包括算数类型和空类型,这些类型有:布尔类型bool,字符类型char,宽字符类型wchar_t,Unicode字符char16 ...
- C++ Primer Plus阅读笔记
cin进行文本输入 使用cin获取字符的基本方式 char ch; cin >> ch; cin读取char值时将忽略空格和换行符.此外,发送给cin的输入被缓冲.这意味着只有在用户按下回 ...
- C-C Primer Plus阅读笔记
常用头: stdio.h string.h inttypes.h limits.h float.h 1.打印short.long.long long和unsigned #include <std ...
- C++ primer笔记 -变量和基本类型
由于头文件会被包含在多个源文件中,所以不应该含有变量或者函数的定义.但又三个列外: 1.头文件可以定义类 2.值在编译时就已经知道的const对象(const对象默认为定义它的文件的局部变量,即在.c ...
- C++ Primer 随笔 Chapter 2 变量和基本类型
2.1C++内置类型 C++ 算术类型 类型 含义 最小存储空间(随机器不同而不同) bool 布尔型 --- char 字符型 8位 wchar_t 宽字符型 16位 short 短整型 16位 i ...
- 【读书笔记】C++ primer 5th 从入门到自闭(一)
这几天看了C++ primer 5th的一二章,有很多收获,但是有的地方因为翻译的问题也搞得理解起来颇为难受啊啊啊啊.尤其是const限定符,在C语言并没有这么多复杂的语法,在C++里面语法细节就多的 ...
随机推荐
- MySQL增加多用户及数据库
登录MYSQL(有ROOT权限),这里以ROOT身份登录: @>mysql -u root -p @>密码 首先为用户创建一个数据库(yc): mysql>create databa ...
- 关于JDBC的学习
一.JDBC简介 JDBC是连接java应用程序和数据库之间的桥梁. 什么是JDBC? Java语言访问数据库的一种规范,是一套API. JDBC (Java Database Connectivit ...
- 嵌入式数据库 sqllite & h2 utils
使用场景: 简单脚本,但是有需要数据记录. (使用前升级下版本) 我的使用: 老机器,老项目,jkd6, 需要记录 SqlLiteUtils package com.sea.edi.listener ...
- Spring-传统方式(XML)创建webapp
如何搭建一个传统的webapp项目[Java后端] 使用xml 来搭建 SSM 环境,要求 Tomcat 的版本必须在 7 以上 QuickStart 1创建工程 创建一个新模块[普通的 Maven ...
- PHP 循环语句
循环机构,在一定的控制下,对此执行. 在PHP中,有以下几种循环 for循环.while循环.do-while循环.forech循环(针对数组) for 循环 语法 for (条件1;条件2;条件3) ...
- MAC范洪攻击-macof
macof 目的:攻击交换机的路由表,实现网络信息嗅探 macof是dsniff中的一个小工具 概要:交换机中存在着一个记录着MAC地址的表,为了完成数据的快速转发,这个表有着自动学习机制,学习后可以 ...
- 对Javaweb的相关练习之利用.jsp文件和.java文件将输入的数据存储到指定的数据库中
练习分析 import javax.servlet.*; import javax.servlet.annotation.WebServlet; import javax.servlet.http.* ...
- HashMap 与 ConcurrentHashMap 底层实现
系统性学习,异步IT-BLOG 一.HashMap 底层源码 JDK7 版本(数组+链表) 我们存放的 hashMap 都会封装成一个节点对象 Entry(key,value),然后将此节点对象存放到 ...
- IO 流分类
更多内容,前往 IT-BLOG 一.File File 类(磁盘操作)可以用于表示文件和目录的信息,但是它不表示文件的内容.递归地列出一个目录下所有文件: 1 public static void l ...
- 【牛客小白月赛69】题解与分析A-F【蛋挞】【玩具】【开题顺序】【旅游】【等腰三角形(easy)】【等腰三角形(hard)】
比赛传送门:https://ac.nowcoder.com/acm/contest/52441 感觉整体难度有点偏大. 作者:Eriktse 简介:19岁,211计算机在读,现役ACM银牌选手力争以通 ...