2. 变量与数据类型:基本数据类型、变量声明与初始化、常量、类型转换

好,咱们今天聊聊变量和数据类型。这是C++里最基础的东西,但说实话,我见过不少老手在这上面翻车。我自己刚入行那会儿,也踩过几个坑,今天一并分享给你。

2.1 基本数据类型:int、float、char、bool

C++里内置了几种基本数据类型。说白了,就是用来存不同种类数据的“容器”。

类型 关键字 大小(通常) 取值范围
整型 int 4字节 -2^31 ~ 2^31-1
浮点型 float 4字节 约 ±3.4e-38 ~ ±3.4e38
字符型 char 1字节 -128 ~ 127 或 0 ~ 255
布尔型 bool 1字节 true 或 false

嗯,这里要注意:int 的大小其实跟平台有关。在32位系统上是4字节,64位系统上通常也是4字节。我当年在嵌入式项目里吃过这个亏——以为 int 永远是4字节,结果在某个16位单片机上编译,它只有2字节,数据直接溢出了。

2.2 变量声明与初始化

变量声明,就是告诉编译器:“嘿,我要用一块内存,名字叫xxx。” 初始化呢,就是往这块内存里放个初始值。

我个人习惯,声明变量时尽量同时初始化。为什么?因为未初始化的变量里存的是“垃圾值”,你永远不知道它是什么。我曾经调试过一个bug,查了两天才发现是一个局部变量没初始化,导致程序行为随机崩溃。

#include <iostream>
using namespace std;

int main() {
    // 声明并初始化
    int age = 25;
    float pi = 3.14159f;
    char grade = 'A';
    bool isReady = true;

    // 也可以先声明,后赋值
    int count;
    count = 10;

    // C++11 统一初始化语法(推荐)
    int score{95};
    float temperature{36.5f};

    cout << "age: " << age << endl;
    cout << "pi: " << pi << endl;
    cout << "grade: " << grade << endl;
    cout << "isReady: " << isReady << endl;
    cout << "count: " << count << endl;
    cout << "score: " << score << endl;
    cout << "temperature: " << temperature << endl;

    return 0;
}
小技巧: 用花括号 {} 初始化有个好处——它能防止“窄化转换”。比如 int x{3.14}; 会编译报错,因为 double 转 int 可能丢失精度。而 int x = 3.14; 只会默默截断,容易埋坑。

2.3 常量

常量就是值不能变的变量。C++里有两种常用方式:constconstexpr

  • const:运行时常量,值在初始化后不能修改。
  • constexpr:编译期常量,值在编译时就确定了。
#include <iostream>
using namespace std;

int main() {
    const double PI = 3.1415926535;
    constexpr int MAX_SIZE = 1024;

    // PI = 3.14;  // 错误!不能修改常量
    // MAX_SIZE = 2048; // 错误!

    cout << "PI: " << PI << endl;
    cout << "MAX_SIZE: " << MAX_SIZE << endl;

    return 0;
}

我个人建议:能用 constexpr 就用 constexpr。因为编译期求值能提升性能,而且更安全。我在做游戏引擎时,很多配置参数都用 constexpr,编译完就直接嵌入代码里了,运行时零开销。

注意: 常量必须在声明时初始化。你不能先声明一个 const int x; 然后再赋值。编译器会直接报错。

2.4 类型转换

类型转换,就是把一种数据类型变成另一种。C++里分两种:隐式转换和显式转换。

隐式转换

编译器自动帮你转。比如 intfloat,或者 charint。但有时候会出问题——比如 floatint 会丢失小数部分。

int a = 10;
float b = a;  // 隐式转换:int -> float,没问题

float c = 3.99;
int d = c;    // 隐式转换:float -> int,d 变成 3,小数丢了

显式转换

你主动告诉编译器:“我就是要转,出问题我自己负责。” 常用方式有 C 风格和 C++ 风格。

#include <iostream>
using namespace std;

int main() {
    double price = 19.99;

    // C 风格转换(不推荐)
    int priceInt1 = (int)price;

    // C++ 风格转换(推荐)
    int priceInt2 = static_cast<int>(price);

    cout << "price: " << price << endl;
    cout << "priceInt1: " << priceInt1 << endl;
    cout << "priceInt2: " << priceInt2 << endl;

    return 0;
}
核心原则: 尽量用 static_cast 而不是 C 风格转换。因为 static_cast 在编译时做类型检查,能提前发现一些不合理的转换。我见过太多因为 C 风格转换导致的隐蔽 bug 了。

2.5 知识体系图

下面这张图帮你理清本章的核心脉络。变量和数据类型的关系,以及常量和类型转换的位置,一目了然。

变量与数据类型 基本数据类型 int(整型) float(浮点型) char(字符型) bool(布尔型) 变量声明与初始化 声明语法 初始化方式 常量 & 类型转换 const / constexpr | 隐式转换 / static_cast

2.6 避坑指南

  • 未初始化变量:我曾经在写网络协议栈时,一个 int 变量没初始化,结果在特定条件下它是个随机值,导致校验和算错,整整排查了两天。记住:声明时顺手初始化。
  • 浮点数比较:别直接用 == 比较两个 float。因为浮点数有精度误差。用 fabs(a - b) < 1e-6 这种形式更靠谱。
  • char 是有符号还是无符号? 这取决于编译器。如果你要存 0~255 的值,明确用 unsigned char,别指望 char 默认是无符号的。
  • 类型转换别滥用:能用隐式转换就别用显式转换。但如果你必须转,用 static_cast 而不是 C 风格。我见过有人用 (int*) 乱转指针,结果程序直接崩了。

好了,这一章的内容就这些。变量和数据类型是C++的基石,你把它搞扎实了,后面学指针、类、模板都会轻松很多。记住我上面说的那些坑,写代码时多留个心眼。


公众号:蓝海资料掘金营,微信deep3321