文章目录
- Void
- 整数
- 有符号整数
- 无符号整数
- 固定宽度的整数和size_t
- 浮点数
- 布尔值
- 字符
- 类型转换
Void
Void
是最容易解释的数据类型。void = 没有类型
不返回值的函数
最常见的是,void 用于指示函数不返回值:
void writeValue(int x)
{
std::cout << "The value of x is: " << x << '\n';
}
如果使用 return 语句尝试在此类函数中返回值,则会导致编译错误:
void noReturn(int x) // void here means no return value
{
std::cout << "The value of x is: " << x << '\n';
return 5; // error
}
已弃用:不采用参数的函数
在 C 语言中,void 用于指示函数不采用任何参数:
int getValue(void) // void here means no parameters
{
int x{};
std::cin >> x;
return x;
}
但这种关键字 void 的使用在 C++ 中被视为已弃用。以下代码是等效的,在 C++ 中是首选的:
int getValue() // empty function parameters is an implicit void
{
int x{};
std::cin >> x;
return x;
}
整数
有符号整数
整数是一种整数类型,可以表示正整数和负整数,包括 0(例如 -2、-1、0、1、2)。C++ 有 4 种主要基本整数类型可供使用:
类型 | 最小范围 | 注意 |
---|---|---|
short int | 16 bits(位) | |
int | 16 bits(位) | 在现代架构上通常为 32 位 |
long int | 32 bits(位) | |
long long int | 64 bits(位) |
定义有符号整数
short s; // 用short代替short int
int i;
long l; // 选择“long”而不是“long int”
long long ll; // 选择“long long”而不是“long long int”
整数类型还可以采用可选的 signed 关键字,但是,不应使用此关键字,因为它是多余的,因为默认情况下整数是有符号的。
有符号整数范围
类型 | 范围 |
---|---|
8 位有符号 | -128 ~ 127 |
16 位有符号 | -32,768 ~ 32,767 |
32 位有符号 | -2,147,483,648 ~ 2,147,483,647 |
64 位有符号 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
无符号整数
要定义无符号整数,我们使用 unsigned 关键字。按照惯例,它放在以下类型之前:
unsigned short us;
unsigned int ui;
unsigned long ul;
unsigned long long ull;
无符号整数范围
类型 | 范围 |
---|---|
8 位有符号 | 0 ~ 255 |
16 位有符号 | 0 ~ 65,535 |
32 位有符号 | 0 ~ 4,294,967,295 |
64 位有符号 | 0 ~18,446,744,073,709,551,615 |
n 位无符号变量的范围为 0 0 0到 ( 2 n ) − 1 (2^n)-1 (2n)−1。
应该避免使用无符号整数:
- 首先,对于带符号值,需要做一些工作才能意外溢出范围的顶部或底部,因为这些值远非 0。对于无符号数字,溢出范围的底部要容易得多,因为范围的底部是 0,它接近我们大多数值的位置。
- 其次,更隐蔽的是,当您混合有符号和无符号整数时,可能会导致意外行为。在 C++ 中,如果数学运算(例如算术或比较)有一个有符号整数和一个无符号整数,则有符号整数通常会转换为无符号整数。因此,结果将是无符号的。
固定宽度的整数和size_t
C99 定义了一组固定宽度的整数(在 stdint.h 标头中),这些整数保证在任何架构上都是相同的大小。
名称 | 类型 | 范围 |
---|---|---|
std::int8_t | 1 byte signed | -128 ~ 127 |
std::uint8_t | 1 byte unsigned | 0 ~ 255 |
std::int16_t | 2 byte signed | -32,768 ~ 32,767 |
std::uint16_t | 2 byte unsigned | 0 ~ 65,535 |
std::int32_t | 4 byte signed | -2,147,483,648 ~ 2,147,483,647 |
std::uint32_t | 4 byte unsigned | 0 ~ 4,294,967,295 |
std::int64_t | 8 byte signed | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
std::uint64_t | 8 byte unsigned | 0 ~ 18,446,744,073,709,551,615 |
C++ 正式采用这些固定宽度的整数作为 C++11 的一部分。可以通过包含标头来访问它们,标头在 std 命名空间中定义它们。下面是一个示例:
#include <cstdint> // for fixed-width integers
#include <iostream>
int main()
{
std::int16_t i{5};
std::cout << i << '\n';
return 0;
}
_t 后缀
较新版本的 C++ 中定义的许多类型(例如 std::nullptr_t)都使用 _t 后缀。此后缀的意思是“类型”,它是应用于现代类型的常见命名法。
如果您看到带有 _t 后缀的内容,则它可能是一种类型。但许多类型没有_t后缀,因此这并不能始终如一地应用。
固定宽度的整数有两个缺点:
- 首先,不能保证在所有体系结构上都定义固定宽度的整数。
- 其次,如果使用固定宽度的整数,则在某些体系结构上,它可能比更宽的类型慢。
浮点数
有三种不同的浮点数据类型:float、double 和 long double。与整数一样,C++ 不定义这些类型的实际大小(但它保证最小大小)。
在现代架构上,浮点表示几乎总是遵循 IEEE 754 二进制格式(由 William Kahan 创建)。在这种格式中,浮点数为 4 个字节,double 为 8 个字节,长 double 可以等效于 double(8 字节)、80 位(通常填充为 12 个字节)或 16 个字节。
浮点数据类型始终是有符号的(可以保存正值和负值)。
类型 | 最小尺寸 | 常用尺寸 |
---|---|---|
float | 4 bytes | 4 bytes |
double | 8 bytes | 8 bytes |
long double | 8 bytes | 8, 12, or 16 bytes |
以下是浮点变量的一些定义:
float fValue;
double dValue;
long double ldValue;
使用浮点运算文本时,请始终至少包含一位小数(即使小数点为 0)。这有助于编译器了解该数字是浮点数而不是整数。
int x{5}; // 5 means integer
double y{5.0}; // 5.0 is a floating point literal (no suffix means double type by default)
float z{5.0f}; // 5.0 is a floating point literal, f suffix means float type
请注意,默认情况下,浮点文本默认为 double 类型。f 后缀用于表示 float 类型的文本。
浮点范围
IEEE 754 表示:
浮点精度
浮点类型的精度定义了它可以表示多少有效数字而不会丢失信息。
双精度值的精度在 15 到 18 位之间,大多数双精度值至少有 16 位有效数字。Long double 的最小精度为 15、18 或 33 位有效数字,具体取决于它占用的字节数。
浮点类型只能精确地表示一定数量的有效数字。使用有效位数多于最小值的值可能会导致值存储不准确。
NaN 和 Inf
浮点数有两个特殊类别:
- 第一个是 Inf,它代表无穷大。Inf 可以是正数或负数。
- 第二个是NaN,代表“不是数字”。
布尔值
布尔变量是只能有两个可能值的变量:true 和 false。
要声明布尔变量,我们使用关键字 bool。
bool b1 { true };
bool b2 { false };
b1 = false;
bool b3 {}; // default initialize to false
整数到布尔值的转换
使用整数初始化变量,初始化bool值:
#include <iostream>
int main()
{
bool bFalse { 0 }; // okay: initialized to false
bool bTrue { 1 }; // okay: initialized to true
bool bNo { 2 }; // error: narrowing conversions disallowed
std::cout << bFalse << bTrue << bNo << '\n';
return 0;
}
上面在 bNo 初始化 2 时报错。
但是,整数可以转换为布尔值 :
#include <iostream>
int main()
{
std::cout << std::boolalpha; // print bools as true or false
bool b1 = 4 ; // copy initialization allows implicit conversion from int to bool
std::cout << b1 << '\n';
bool b2 = 0 ; // copy initialization allows implicit conversion from int to bool
std::cout << b2 << '\n';
return 0;
}
字符
char 数据类型设计为保存单个字符,可以是单个字母、数字、符号或空格。
char 数据类型是整数类型,这意味着基础值存储为整数。
初始化字符
可以使用字符文本初始化 char 变量:
char ch2{ 'a' }; // initialize with code point for 'a' (stored as integer 97) (preferred)
也可以使用整数初始化字符,但如果可能,应避免这样做
char ch1{ 97 }; // initialize with integer 97 ('a') (not preferred)
打印字符
#include <iostream>
int main()
{
char ch1{ 'a' }; // (preferred)
std::cout << ch1; // cout prints character 'a'
char ch2{ 98 }; // code point for 'b' (not preferred)
std::cout << ch2; // cout prints a character ('b')
return 0;
}
字符大小、范围和默认符号
Char 由 C++ 定义为大小始终为 1 字节。
默认情况下,字符可以是有符号的,也可以是无符号的(尽管它通常是有符号的)。如果使用字符来保存 ASCII 字符,则无需指定符号(因为有符号和无符号字符都可以保存介于 0 和 127 之间的值)。
如果使用 char 来保存小整数(除非显式优化空间,否则不应这样做),则应始终指定它是有符号还是无符号。有符号的字符可以保存介于 -128 和 127 之间的数字。无符号字符可以保存 0 到 255 之间的数字。
将符号放在单引号和双引号中有什么区别
- 单个字符总是放在单引号中:一个字符只能代表一个符号。
- 双引号之间的文本:被视为多个字符的字符串。
类型转换
隐式类型转换
当编译器在没有我们明确询问的情况下代表我们进行类型转换时,我们称之为隐式类型转换。
#include <iostream>
void print(double x) // print takes a double parameter
{
std::cout << x << '\n';
}
int main()
{
print(5); // what happens when we pass an int value?
return 0;
}
某些类型转换始终是安全的,而其他类型转换可能会导致在转换过程中更改值。不安全的隐式转换通常会生成编译器警告,或者(在大括号初始化的情况下)错误。
这是大括号初始化是首选初始化形式的主要原因之一。大括号初始化将确保我们不会尝试使用初始值设定项初始化变量,该变量在隐式类型转换时会丢失值:
int main()
{
double d { 5 }; // okay: int to double is safe
int x { 5.5 }; // error: double to int not safe
return 0;
}
显式类型转换
通过 static_cast 运算符进行显式类型转换。
static_cast<new_type>(expression)
示例:
#include <iostream>
void print(int x)
{
std::cout << x << '\n';
}
int main()
{
print( static_cast<int>(5.5) ); // explicitly convert double value 5.5 to an int
return 0;
}