1.程序编译基础知识
1.源文件&目标文件
创建一个firstcpp的项目打开其源文件路径如下图:
path = C:\Users\Excub\workspace\VisualStudioProject\firstcpp

1.代码文件:.h 和 .cpp。其中.h是用来做引用的,每个.cpp是单独编译的
2.项目配置:
(1)项目配置文件:.vcxproj
(2)解决方案配置文件:.sln
3.项目中的特殊配置文件:.filters
4.特定的设置(例:调试的路径):.user
解决方案配置文件是可以配置多个项目的配置,项目的配置文件是配置单独项目的。一个项目对应一个解决方案,一个解决方案可以有多个项目。
c++文件经过代码编译后执行的,所以我们也需要知道目标文件
(1).obj文件:每个.cpp代码执行文件运行后会生成一个obj文件。
(2).exe文件:多个obj文件会合并成一个.exe的执行文件,双击可以运行。
obj 文件路径:path\firstcpp\x64\Debug\firstcpp.obj
exe文件路径:path\x64\Debug\firstcpp.exe
补充:调试文件:path\x64\Debug\firstcpp.pdb
2.程序编译的过程
c++编译的过程:
预处理->编译->汇编->链接->执行
1.预处理:#include 主要将.h文件复制过来,输出为.cpp。
(找不到文件的错误)
2.编译:把cpp代码转化目标机器系统的汇编代码,输出为.s即汇编码(注意:每个cpp文件是单独编译的)
3.汇编:代码编译为机器指令,输出为.obj的文件/其他系统.o文件。
(语法错误会在此编译和汇编阶段发生)
4.链接:将多个.obj文件合并,设置程序入口,输出为.exe。
(多个cpp中有重复定义的问题可能会在此阶段报错,因为cpp是单独编译的,在此阶段报错)
5.执行:加载.exe中程序和依赖的动态库,机器指令代码到内存。
(动态库的加载,内存溢出等问题在此阶段才会报错)
2.变量的一生
变量的本质:变量名+值的类型+修改算法。
1.变量名决定了变量的名称->指向特定类型的内存空间。
2.变量值的类型决定了变量在内存中占据多大空间。
3.修改算法决定了变量的修改方式。
1.变量的基本属性
基础数据类型所占内存大小,一格代表1个字节。
我们通常使用不占用性能开销的sizeof来查看数据类型所占内存大小。
我们可以通过**&变量名** ->得到其内存地址。

cpp
#include <iostream>
//命名空间输出简化
using namespace std;
int main()
{
std::cout << "Hello World!\n";
//定义一个int类型的变量x
int x{ 100 };
cout << "x=" << x << endl;
cout << "变量x的原本内存地址" << &x << endl;
//简单的类型转换
cout << "变量x的内存地址"
<< (long long) & x
<< endl;
int c{ 200 };
cout << "变量z的内存地址"
<< (long long)&c
<< endl;
//sizeof()获取变量所占内存中的内存大小
cout << "x的内存大小"
<< sizeof(x) << "字节"
<< endl;
long long bigint{ 0 };
cout << "bigint的内存大小"
<< sizeof(bigint)<<"字节"
<< endl;
}

2.变量的算数运算
变量:可修改的容器。
字面量:直接写在代码中的固定值,固定不变的数据本身。
C++计算的注意点:
1.基础算数运算c++都支持,运算的遵循先乘除后加减,复合运算建议用括号进行囊括计算。
2.+=、-=、/=、*=和其他语言计算一样,支持简化版加减乘除。
3.除法的特殊性:分母不能为0。
4.现代版C++学习中自增,自减。 z++(先取值再++)和++z(先++再取值)。现代编程用++z来进行自增自减,(算法层面)目前是节省内存,减少一个临时变量。
3.cpp浮点数的计算与转换
注意点:
1.变量在进行除法计算时,需进行除数不为0的算前验证判断,否则就会导致编译程序不报错,但是运行时,程序出错。
2.c++中将浮点数转为整数是不会进行四舍五入的,而是直接截取保留整数部分。注意变量之间的计算结果可能精度上有误差。
3.c++中整数计算,如果想要结果是浮点数,则必须对计算的整数其中之一转化为浮点数参与计算才可以,直接对结果类型转换无效。
cpp
//整数相除会丢失小数位
int x1{ 1 };
int x2{ 2 };
float f1{ 0 };
f1 = x1 / x2;
cout << "f1 = " << f1 << endl; //f1=0
//解决方法,计算的两个数之间有一个数是浮点数则结果就是浮点数
cout << "1 / 2. = " << 1/2. << endl;
//那么上述f1的计算经过数据类型转换后如下
f1 = x1 / (float)x2;
cout << "转换后的f1=" << f1 << endl; //f1=0

4.变量的作用域和生命周期
作用域:定义了一个变量后,在哪里可以使用。
生命周期:变量对应的这块内存空间什么时候占用,什么时候释放,从定义的那一行代码开始暂用内存,出了大括号后释放。
局部变量:在一对大括号里面定义的变量,定义后即申请内存,在出了大括号之后就释放内存。
全局变量:在main函数(入口函数)的外部申请内存,在main结束之后才释放。
注意:子作用域中可以访问父作用域的变量,父作用域不可以访问子作用域的变量。子和父作用域的变量可以重名,调用时遵循就近原则。
3.常量
本质:相对于变量,是不允许变化的量。
cpp
//常量的定义和分类
//运行时常量定义 (普通常量)
const int x{ 0 };
//编译时常量定义 (表达式常量)
constexpr int cx{ 1 };
运行时常量:顾名思义,在运行时才知道的常量。
编译时常量:顾名思义,在编译的时候就已经确定的常量。
运行时常量特性:可能编译的时候值是无法确定的,可能由外部传入,计算完之后才不可更改。
⭐(常用)编译时常量特性:不能通过运行时产生的变量来对其进行赋值,因为其在编译阶段已经确定好值了。
⭐大部分时候用编译时常量(constexpr),涉及到参数传递赋值的时候选用运行时常量(const)
cpp
//运行时常量
const int cx{ 100 };
cout << "cx = " << cx << endl;
int t1 = 10;
const int cx2{ t1 + 10 };
cout << "运行时常量cx2 = " << cx2 << endl;
//编译时常量
constexpr int cex{ 300 };
cout << "cex = " << cex << endl;
//直接报错,无法用变量初始化编译时常量
//constexpr int cx3{ t1 + 10 };
4.auto的使用
auto的作用:能根据实际情况自动推导变量类型,提高代码简洁性。
1.auto 确保变量被初始化
2.代码更加简洁、后面的泛型变成用的多
3.简化代码,比如迭代器代码简化,并替换容器后代码可以不变
4.从初始化器推导类型
⭐常用定义变量:变量类型计算更改,则变量定义处不用变。
auto ax = 1;
⭐常用接受函数返回值时,返回值类型变化后引用是用auto定义的,所以其后续使用不用变,减少维护成本。
cpp
//auto的基础使用
#include <iostream>
using namespace std;
int main() {
// 1. 基础数值类型推导
auto num = 10; // 推导为 int(字面量10是int)
auto pi = 3.14159; // 推导为 double(默认浮点是double)
auto f = 5.0f; // 推导为 float(加f后缀)
auto c = 'A'; // 推导为 char
auto ptr = # // 推导为 int*(指针类型)
cout << "num类型推导为int:" << num << endl;
cout << "ptr类型推导为int*:" << *ptr << endl;
return 0;
}
常量推导
auto推导const变量时,默认丢掉 "顶层 const"(变成普通变量);- 加
const auto/constexpr auto才能得到常量。
cpp
#include <iostream>
using namespace std;
int main() {
int a = 20;
const int b = 30;
// 1. 普通auto:忽略顶层const(b是const int,但auto推导为int)
auto x = b;
x = 40; // 可以修改,因为x是普通int
// 2. const auto:运行时常量(只读,不可修改)
const auto y = a;
// y = 50; // 报错!const auto是只读变量
// 3. constexpr auto:编译时常量(编译期确定值,可用于编译期上下文)
constexpr auto z = 100;
int arr[z] = {1,2,3}; // 编译期常量可用于数组大小
cout << "const auto y(运行时常量):" << y << endl;
cout << "constexpr auto z(编译时常量):" << z << endl;
return 0;
}
5.案例分析:
#YUV和RGB互相转换,MP4视频播放常见格式就是YUV
YUV:Y亮度,U 蓝色差,V红色差。
RGB:红绿蓝。
cpp#代码实现互转 #include <iostream> #include <algorithm> // 用于std::clamp(C++17及以上) using namespace std; // 数值范围提示(可选,增强友好性) constexpr int RGB_MIN = 0; constexpr int RGB_MAX = 255; int main() { int choice{}; cout << "===== 颜色空间转换工具 =====" << endl; cout << "1. YUV → RGB" << endl; cout << "2. RGB → YUV" << endl; cout << "请输入转换选项(1/2):"; cin >> choice; // 处理YUV转RGB if (choice == 1) { double Y, U, V; cout << "\n请输入YUV分量(Y范围:0~255,U/V范围:0~255):" << endl; cout << "Y = "; cin >> Y; cout << "U = "; cin >> U; cout << "V = "; cin >> V; // YUV转RGB公式(BT.601标准) double R = Y + 1.13983 * (V - 128); double G = Y - 0.39465 * (U - 128) - 0.58060 * (V - 128); double B = Y + 2.03211 * (U - 128); // 限制RGB范围在0~255(使用std::clamp简化逻辑) R = clamp(R, (double)RGB_MIN, (double)RGB_MAX); G = clamp(G, (double)RGB_MIN, (double)RGB_MAX); B = clamp(B, (double)RGB_MIN, (double)RGB_MAX); cout << "\n转换结果(RGB):" << endl; cout << "R = " << R << endl; cout << "G = " << G << endl; cout << "B = " << B << endl; } // 处理RGB转YUV else if (choice == 2) { int R, G, B; cout << "\n请输入RGB分量(范围:0~255):" << endl; cout << "R = "; cin >> R; cout << "G = "; cin >> G; cout << "B = "; cin >> B; // 校验RGB输入合法性 if (R < RGB_MIN || R > RGB_MAX || G < RGB_MIN || G > RGB_MAX || B < RGB_MIN || B > RGB_MAX) { cout << "错误:RGB值必须在0~255之间!" << endl; return 1; } // RGB转YUV公式(BT.601标准) double Y = 0.299 * R + 0.587 * G + 0.114 * B; double U = -0.14713 * R - 0.28886 * G + 0.436 * B + 128; // 偏移128到0~255范围 double V = 0.615 * R - 0.51498 * G - 0.10002 * B + 128; // 修正原公式符号(原公式V计算有误) cout << "\n转换结果(YUV):" << endl; cout << "Y = " << Y << endl; cout << "U = " << U << endl; cout << "V = " << V << endl; } // 处理无效选项 else { cout << "错误:无效的选项!请输入1或2。" << endl; return 1; } return 0; }
6.总结
本章节是笔者记录C++学习的时候的精讲部分笔记,用于自己学习和记录。