基本数据类型

数据类型(Data Type)是⼀种属性,它告诉编译器如何解释存储在计算机内存中的某段数据。数据类型决定了数据的存储⼤⼩、布局、值范围以及可以对该数据执⾏哪些操作。

C++ 提供了多种数据类型,包括基本数据类型、复合数据类型和特殊数据类型,本篇主要讲解的是 C++ 的基本数据类型。

基本数据类型分为整数型浮点型字符型布尔型空类型。它们在各自对应的应用场景中都有着不可或缺的重要性,接下来对这些数据类型进行逐步的学习。

整数型

整数型可以理解为在内存中开辟一个专门用于存储整数的空间,根据要存放的数字大小以及是否需要表示负数,可以采用不同的整数型关键字来开辟所需大小的空间。

在 C++ 中,整数类型(如 int、char、int8_t 等)分为 ** 有符号(signed)和无符号(unsigned)** 两种,核心区别是:是否能表示负数、二进制最高位的用途、数值范围。

|对比项 | 有符号类型 signed | 无符号类型 unsigned | | 能否存负数 | 可以 | 不可以(只能 ≥0)| |最高位含义| 是符号位(0 = 正,1 = 负) |是数值位(参与计算)| |取值范围| 正负对半分 |从 0 开始到更大的正数|

位数相同,无符号类型能表示的正数更大,有符号类型能表示负数。

有符号整数类型

类型

占用字节

存储范围

short

2

-32,76832,767

int

4

-2,147,483,6482,147,483,647

long

4 或 8

依赖于系统和编译器

long long

8

-9,223,372,036,854,775,8089,223,372,036,854,775,807

无符号整数类型

通过在有符号整数类型前添加 unsigned 关键字,可以得到对应的无符号整数类型,无符号整数只能表示非负数(零和正数)。

类型

占用字节

存储范围

unsigned short

2

0 到 65535

unsigned int

4

0 到 4294967295

unsigned long

4 或 8

依赖于系统和编译器

unsigned long long

8

0 到 18446744073709551615

固定宽度整数类型

从 C++ 11 开始引入了固定宽度整数类型,确保在不同平台上具有相同的大小。

类型

说明

存储范围

int8_t

8 位有符号整数

-128 到 127

uint8_t

8 位无符号整数

0 到 255

int16_t

16 位有符号整数

-32768 到 32767

uint16_t

16 位无符号整数

0 到 65535

int32_t

32 位有符号整数

-2147483648 到 2147483647

uint32_t

32 位无符号整数

0 到 4294967295

int64_t

64 位有符号整数

-9223372036854775808 到 9223372036854775807

uint64_t

64 位无符号整数

0 到 18446744073709551615

代码演示:

#include <iostream>
#include <cstdint> // 包含固定宽度整数类型

int main() {
    short s = 32767;
    int i = 2147483647;
    long l = 2147483647;
    long long ll = 9223372036854775807;
    
    unsigned int ui = 4294967295;
    int32_t i32 = 2147483647;
    uint64_t ui64 = 18446744073709551615ULL;

    std::cout << "短整型: " << s << std::endl;
    std::cout << "整型: " << i << std::endl;
    std::cout << "长整型: " << l << std::endl;
    std::cout << "超长整型: " << ll << std::endl;
    std::cout << "无符号整型: " << ui << std::endl;
    std::cout << "32位整型: " << i32 << std::endl;
    std::cout << "64位无符号整型: " << ui64 << std::endl;
}

注意

如果存储的数值超出了数据类型所能表示的范围,会发生 整数溢出 。有符号整数溢出是未定义行为,可能导致程序崩溃或产生不可预期的结果。无符号整数溢出则是定义良好的,会对最大值+1取模。

代码演示:

#include <iostream>

int main() {
    // 有符号整数溢出 - 未定义行为
    int i = 2147483648;
    std::cout << "溢出后的有符号整数: " << i << std::endl;
    
    // 无符号整数溢出 - 定义良好的行为
    unsigned int ui = 4294967296;
    std::cout << "溢出后的无符号整数: " << ui << std::endl;
}

浮点型

对于需要存储小数的场景,我们需要使用浮点数据类型来存储,例如:3.14。浮点数用于表示实数,可以表示非常大或非常小的数值,但精度有限。

类型

占用大小

十进制精度位数

数值范围(近似)

float

4

约 6-7 位

1e-38 到 1e38

double

8

约 15-16 位

1e-308 到 1e308

long double

8, 12, 或 16

double 更高

double 更大

代码演示:

#include <iostream>

int main() {
    double d1 = 3.14;         // 标准小数表示
    double d2 = 3.14e10;      // 科学计数法(3.14 x 10^10)
    double d3 = 3.14e-10;     // 科学计数法(3.14 x 10^-10)
    float f = 3.14f;           // float类型(带f后缀)
    long double ld = 3.14L;    // long double类型(带L后缀)
    
    std::cout << "标准小数: " << d1 << std::endl;
    std::cout << "科学计数法(大): " << d2 << std::endl;
    std::cout << "科学计数法(小): " << d3 << std::endl;
}

注意

浮点类型可以表示非常大或非常小的数,但它们只能近似地表示小数,因为它们在内存中的表示是基于二进制分数的。

浮点类型在计算机中的表示有时会导致出现精度问题,因此在需要进行精确计算的场景(如金融计算)中,应该考虑使用专门的库或整数类型(如定点数)而不是浮点类型。

字符型

字符型用于存储单个字符,如字母、数字、标点符号等。C++ 提供了多种字符类型以支持不同的字符集。

类型

占用字节

说明

char

1

用于存储单个字符,通常是ASCII字符。有符号性取决于编译器

signed char

1

明确的有符号字符类型,范围通常是 -128127

unsigned char

1

明确的无符号字符类型,范围通常是 0255

wchar_t

2 或 4

宽字符类型,用于表示更大的字符集(如Unicode),大小取决于编译器

char16_t

2

16位字符类型,用于UTF-16编码(C++11起)

char32_t

4

32位字符类型,用于UTF-32编码(C++11起)

char 数据类型通常只能用来存储一个字符,也就是 '1' / 'A' 这种单个的字符。如果想要存储一句话这种长字符序列,就需要用到 字符数组字符串类(如 std::string)来实现。

代码演示:

#include <iostream>

int main() {
    char character = 'A';
    signed char sc = -128;
    unsigned char uc = 255;
    
    std::cout << "字符: " << character << std::endl;
    std::cout << "字符的ASCII值: " << int(character) << std::endl;
    std::cout << "有符号字符: " << static_cast<int>(sc) << std::endl;
    std::cout << "无符号字符: " << static_cast<int>(uc) << std::endl;
}

布尔型

布尔型也可以称之为逻辑型,这个数据类型只能存储 true (真) / false (假) 两个值。布尔型常用于需要进行逻辑判断的场景。

类型

占用字节

范围

bool

1

只能是 truefalse 两个值

代码演示:

#include <iostream>

int main() {
    bool isTrue = true;
    bool isFalse = false;
    
    std::cout << "isTrue: " << isTrue << std::endl;
    std::cout << "isFalse: " << isFalse << std::endl;

    // 布尔值在算术表达式中会被转换为整数
    std::cout << "true + true = " << isTrue + isTrue << std::endl;
}

空类型

空类型代表着没有类型,它不能用于声明变量,主要使用场景是表示函数没有返回值或者函数不需要接收参数。

类型

说明

void

不表示任何实际的数据类型,用于函数返回值或参数列表

代码演示:

#include <iostream>

// 函数不返回任何值
void printMessage() {
    std::cout << "这个函数不返回任何值" << std::endl;
    // 可以有return语句,但不带任何值
    return;
}

// 函数不接受任何参数
void demo(void) {
    std::cout << "我不接收任何参数,也不返回任何值" << std::endl;
    return;
}

int main() {
    printMessage();
    demo();
}

基本数据类型转换

在 C++ 中,不同类型的数据可以相互转换,但需要注意一些规则和潜在问题

隐式类型转换

编译器会自动进行某些类型转换

代码演示:

#include <iostream>

int main() {
    int i = 42;
    double d = i; // int隐式转换为double
    std::cout << "d = " << d << std::endl;
    
    double pi = 3.14;
    int j = pi; // double隐式转换为int(小数部分被截断)
    std::cout << "j = " << j << std::endl;
    
    // 算术转换:不同类型的操作数会转换为相同类型
    double result = i + pi; // i被转换为double,然后与pi相加
    std::cout << "result = " << result << std::endl;
}

显式类型转换

可以使用显式转换来控制类型转换

代码演示:

#include <iostream>

int main() {
    double pi = 3.14;
    
    // C风格转换
    int i = (int)pi;
    std::cout << "i = " << i << std::endl;
    
    // C++风格转换(推荐)
    int j = static_cast<int>(pi);
    std::cout << "j = " << j << std::endl;
}

注意

类型转换可能导致数据丢失或意外行为,特别是从浮点类型转换为整数类型时,小数部分会被直接截断而不是四舍五入。从大范围类型转换为小范围类型时可能导致溢出。

数据类型选择建议

选择合适的数据类型对于程序的性能、内存使用和正确性都很重要

整数类型选择

  • 默认情况下使用 int,它通常是处理器最自然的大小

  • 当需要节省内存且数值范围较小时,使用 short

  • 当 int 不够用时,使用 long long

  • 当需要确保跨平台一致性时,使用固定宽度整数类型(如 int32_t)

  • 当只需要表示非负数时,考虑使用无符号类型

浮点类型选择

  • 默认情况下使用 double,它提供了良好的精度和性能平衡

  • 当内存非常有限且精度要求不高时,使用 float

  • 当需要更高精度时,使用 long double

字符类型选择

  • 默认情况下使用 char 处理 ASCII 字符

  • 当需要处理 Unicode 字符时,使用 char16_t 或 char32_t

  • 当需要将字符作为小整数使用时,明确使用 signed char 或 unsigned char

sizeof 运算符

sizeof 是一个用于获取数据类型或变量所占内存大小的运算符,返回的结果是以字节为单位的 size_t 类型(无符号整数类型)。

基本语法:

sizeof(类型)
sizeof(变量)
sizeof 表达式  // 对于表达式可以省略括号

代码演示:

#include <iostream>

int main() {
    int a{10};
    double b{3.14};
    
    std::cout << "int 类型大小: " << sizeof(int) << " 字节" << std::endl;
    std::cout << "变量 a 的大小: " << sizeof(a) << " 字节" << std::endl;
    std::cout << "double 类型大小: " << sizeof(double) << " 字节" << std::endl;
    std::cout << "变量 b 的大小: " << sizeof(b) << " 字节" << std::endl;
    
    // sizeof 表达式示例
    std::cout << "表达式大小: " << sizeof(a + b) << " 字节" << std::endl;
    
    // 注意:sizeof 不会计算表达式的结果
    int c = 0;
    std::cout << "sizeof(c = 5) = " << sizeof(c = 5) << std::endl;
    std::cout << "c = " << c << std::endl; // c 仍然是 0,因为 sizeof 没有执行赋值
}

不同平台(32位 / 64位)或编译器下,类型大小可能不同。

sizeof 的特点:

  • 在编译期计算: sizeof(int) 在编译阶段就已经确定

  • 不会执行表达式: sizeof 只关心类型,不会真正执行表达式

  • 返回类型为 size_t:这是一个无符号整数类型,定义在 头文件中