三、基本数据类型和计算(二)

1、字符
#include <iostream>

int main()
{
	std::cout << 65 << std::endl;       //65是一个int类型的整数
	std::cout << (char)65 << std::endl;    //将其转化为1个字节的char类型字符,编码的正向操作
	std::cout << (int)'A' << std::endl;   //编码的逆向操作,将字符转化为数字
}

1)字符数据原理

内存数据 编码规范 显示
65 ASCII A

原理:在内存中最终存储的数据都是数字,字符本质上还是数字,显示什么样的形式,取决于编码规范的实现,上述代码中编码规范的实现是由std::cout类决定的。

ANSI

2)字符数据类型

类型 内存占用 说明
char 1 ascii字符
wchar_t 2/4 宽字节字符,使用L来说明变量
char16_t 2 utf_16字符,使用一个u来说明变量
char32_t 4 utf_32字符,使用一个U来说明变量

①chat类型

#include <iostream>

int main()
{
	char charA{ 'A' };  //使用字符初始化字符,编译器会将字符强制转化为数字
	std::cout << charA << std::endl;

	char charB{ 66 };
	std::cout << charB << std::endl;     //使用数字的方式初始化字符串
	
	charB++;
	std::cout << charB << std::endl; //因字符本质为数字,所以可以进行计算
}

②wchar_t类型

该类型占用两个字节(无论是汉字、数字、字符),因编译器不同,占用的字节数不同(2字节或4字节),定义字符时要通过L来说明字符是一个宽字节字符

#include <iostream>       //
#include <locale>    //设置本地,显示中文需要包含该头文件
int main()
{
	setlocale(LC_ALL, "chs");
	wchar_t wcharA{ L'A' };       //定义时使用L进行说明
	wchar_t wcharB{ L'我' };
	std::wcout << wcharA << std::endl;  //std::cout没有实现对宽字节的编码 
	std::wcout << wcharB << std::endl;
	std::cout << "wchar_t的内存大小为:"<< sizeof(wcharA) << std::endl;
}

④char32_t、char16_t

为实现跨平台的应用,引入了char32_t、char16_t,因为wchar_t因平台不同占用的内存不同

#include <iostream>       //
#include <locale>    //设置本地,显示中文需要包含该头文件
int main()
{


	char16_t char16{ u'a' };
	std::cout << char16 << std::endl;  //std::cout和std::wcout都没有实现对char16_t的编码,因此只能输出数字

	char32_t char32{ u'a' };
	std::cout << char32 << std::endl; //std::cout和std::wcout都没有实现对char32_t的编码,因此只能输出数字
}

3)ASCII编码表

换行可以使用char(10)表示

//换行
#include <iostream>       
int main()
{
	std::cout << "Hello World!!" << char(10);
}

4)练习:用户输入一个小写字母,转化为大写字母后输出

//用户输入一个小写字母,转化为大写字母后输出
#include <iostream>

int main()
{
	char userIn;
	std::cout << "请输入一个小写字母:";
	std::cin >> userIn;
	userIn -= 32;
	std::cout << "转化后的大写字母为:" << userIn << std::endl;

}

2、推断类型

即不告诉编译器使用什么数据类型

1)auto类型

类型定义语法 示例
auto 变量名 {初始值}; auto a {200};

注:auto类型的变量必须初始化,负责编译器无法判断是什么类型的变量

2)查看变量的类型

变量类型查看函数
typeid(变量).name
#include <iostream>

int main()
{
	auto num{ 100 };
	auto charUser{ U'a' };     //auto类型的变量必须初始化
	auto chat_z{ u'A' };

	std::cout << "num的类型为" << typeid(num).name() << (char)10;
	std::cout << "charUser的类型为" << typeid(charUser).name() << (char)10;
	std::cout << "chat_z的类型为" << typeid(chat_z).name() << (char)10;
}

注:日常不推荐使用auto类型,因为代码阅读性不好

3、格式化输出流及转义

1)格式化输出流操作

作用:使用文字输出更美化

注:加粗内容需要使用头文件<iomanip>

格式化输出流 含义 示例
std::fixed 以小数点模式输出浮点数 3.1415926
std::scientific 以科学计数法输出小数 3E100
std::defaultfloat 恢复默认的小数输出,即将上述2个设置取消
std::setprecision(int) 设置小数精度 std::setprecision(2),输出3.14
std::dec 以后输出的数字采用十进制输出 999
std::hex 以后输出的数字采用十六进制输出 FFF
set::oct 以后输出的数字采用八进制输出 777
std::showbase 十六进制和八进制显示前缀 0xFF
std::shownobase 关闭十六进制和八进制显示前缀
std::setw(int) 把输出内容设置宽度,每次都需设置 std::setw(10)输出 999
std::setfill(char) 当显示宽度超过字符快宽度时,用指定字符串填充剩余内容 **************999
std::left 设置字符对其模式为左对齐
std::right 设置字符对其模式为右对齐
//格式化输出及转义

#include <iostream>
#include <iomanip>

int main() {
	std::cout << std::fixed;  //以小数点计数
	std::cout << 3.1415926 << (char)10;

	std::cout << std::scientific;//以科学计数法技术
	std::cout << 3.1415926 << char(10);

	std::cout << std::setprecision(2);  //设置小数精度
	std::cout << 3.1415926 << std::endl;

	std::cout << std::hex; //以16进制输出
	std::cout << 100 << std::endl;

	std::cout << std::oct; //以8进制输出
	std::cout << 100 << std::endl;

	std::cout << std::dec; //以10进制输出
	std::cout << 100 << char(10);

	std::cout<<std::setw(10)  << 2222 << std::endl;     //设置输出宽度
	//当显示宽度超过字符宽度时,剩余部分使用特定字符填充
	std::cout << std::setfill('*') << std::setw(10) << 999 << std::endl; //

	std::cout << std::right; //右对齐
	std::cout << "helloworld" << std::endl;

}

//输出内容

2)转义

转义序列 作用
\n 换行
\\ \
' '
\t 制表符
" "
? ?
\b 退格
\a 警告声
4、运算优先级

1)运算优先表

注:下表运算符从上到下依次优先运算

运算符 关联性
:: 左(从左往右计算)
() [] -> . 后缀++ 前缀-- typeid const_cast dynamic_cast static_cast reinterpret_cast 左(从左往右计算)
! ~ 一元+ 一元- 前缀++ 前缀-- & * (类型)sizeof new new[] delete delete[] 右(从右往左计算)
.* ->* 左(从左往右计算)
* / % 左(从左往右计算)
+ - 左(从左往右计算)
<< >> 左(从左往右计算)
< <= > >= 左(从左往右计算)
== != 左(从左往右计算)
& 左(从左往右计算)
^ 左(从左往右计算)
| 左(从左往右计算)
&& 左(从左往右计算)
|| 左(从左往右计算)
? : op= 右(从右往左计算)
throw 右(从右往左计算)
. 左(从左往右计算)

2)a++和++a的反汇编

#include <iostream>
int main()
{
	int a{ 10 };
	a++;
	++a;

	int b{ 5 };
	int c{};

	c = b + a++; //c=b+a;a=a+1  //后缀优先

	c = b + ++a; //a=a+1;c=b+a
	
	c = 3 * -b++ + a;        //正负在前,乘除、加减在后
	std::cout << c << std::endl;
	c = 2 * -b-- - a;
	std::cout << c << std::endl;
}

①查看汇编的方法:先设置断点,调试->窗口->反汇编

②a++和++a反汇编代码

结论:++a和a++在不执行其他操作的时候,一样

③c = b + a++和c = b + ++a汇编区别


5、字符的故事

常见编码规范

1)ASCII:1个字节,0-127是统一的英文、符号

2)ANSI:操作系统有一个内码,按照操作系统时,选择什么样的语言,操作系统就会给一个本地什么语言的内码页,所有的字符通过内码页进行解读

3)GB2312:国标,汉字用两个字节表示,即两个char,从0x0000~0xFFFF,为了让汉字能够正常显示,需要保证,高位范围00-FF,地位范围00-FE

4)gbk:国标扩

5)GB18030

6)UNICODE:万国码,提供字->数字的映射,UTF-16用最早使用2个字节表示1个字,现在可变长的;UTF-8中因为为1个字节,中文为2-3个字节;UTF-32中,1个字为32字节