c++八股文1
volatile关键字
易变性:就是确保变量的每次读取都从主内存中获取最新值,每次写入都立即反映到主内存中。
因为如果不这样可能在进行写入操作时,会先写入寄存器,这样就使其他线程在读取数据时还是没有更细的数据。
顺序执行:volatile
的第三个特性是保证对 volatile
变量操作的相对顺序。编译器不能对 volatile
操作的顺序进行重排序,必须按照代码中出现的顺序来生成指令。
这种顺序保证是有限的:它只保证 volatile
操作之间的相对顺序,不保证 volatile
操作与非 volatile
操作之间的顺序。也就是说,编译器仍然可能将非 volatile
操作重排序到 volatile
操作之前或之后。
不可优化性:volatile
最重要的作用就是阻止编译器对变量访问进行优化。编译器在优化代码时,通常会假设变量的值只在当前程序的控制下改变,因此可能会进行各种优化,比如:消除"冗余"的读取操作、将变量值缓存到寄存器中、或者完全移除看似无用的代码。
volatile int i;
i = 2;
printf("i: %d",i);
优化为printf("i: %d",2);
编译期(Compile Time)
什么是编译期?
编译期是指源代码被编译器处理转换成机器码的阶段。这个阶段发生在程序运行之前。
编译期的主要工作:
cpp
// 1. 语法检查 int x = "hello"; // ❌ 编译错误:类型不匹配// 2. 类型检查 std::string s = 123; // ❌ 编译错误:不能将int转为string// 3. 模板实例化 template<typename T> T add(T a, T b) { return a + b; }int result = add(1, 2); // 🔄 编译时生成 add<int> 特化版本// 4. constexpr计算 constexpr int size = 100; // 🔄 编译时计算并替换为100 int array[size]; // 🔄 编译时确定数组大小// 5. 宏展开 #define SQUARE(x) ((x)*(x)) int value = SQUARE(5); // 🔄 编译时展开为 ((5)*(5))
编译期的特点:
发生时间:程序运行前
执行者:编译器
输入:源代码文件(.cpp, .h)
输出:可执行文件(.exe, .out)或目标文件(.o)
错误:编译错误(语法错误、类型错误等)
运行期(Run Time)
什么是运行期?
运行期是指编译后的可执行程序实际在操作系统上运行的阶段。
运行期的主要工作:
cpp
#include <iostream> #include <vector>int main() {// 1. 用户输入处理int user_input;std::cout << "Enter a number: ";std::cin >> user_input; // 🔄 运行时获取输入// 2. 动态内存分配std::vector<int> data(user_input); // 🔄 运行时决定向量大小int* array = new int[user_input]; // 🔄 运行时分配内存// 3. 文件操作std::ifstream file("data.txt"); // 🔄 运行时打开文件std::string line;while (std::getline(file, line)) {// 🔄 运行时读取文件内容}// 4. 网络通信// 🔄 运行时建立网络连接,发送接收数据// 5. 异常处理try {if (user_input == 0) throw std::runtime_error("Division by zero");int result = 100 / user_input; // 🔄 运行时可能抛出异常} catch (const std::exception& e) {std::cout << "Error: " << e.what() << std::endl;}delete[] array; // 🔄 运行时释放内存return 0; }
运行期的特点:
发生时间:程序启动后
执行者:CPU(执行机器指令)
输入:用户输入、文件数据、网络数据等
输出:程序运行结果
错误:运行时错误(除零、空指针、内存泄漏等)
两者的直观对比
编译期示例:
cpp
// 所有这些都在编译时完成 constexpr int calculate() { return 2 + 3 * 4; } // 🔄 编译时计算:14 constexpr int result = calculate(); // 🔄 编译时替换为14// 编译后,代码相当于: // constexpr int result = 14;
运行期示例:
cpp
#include <iostream>int calculate_runtime(int a, int b) {return a + b; // 🔄 运行时计算 }int main() {int x, y;std::cin >> x >> y; // 🔄 运行时获取输入int result = calculate_runtime(x, y); // 🔄 运行时函数调用std::cout << result << std::endl; // 🔄 运行时输出return 0; }
为什么需要区分两者?
性能优化
cpp
// 编译期计算(零运行时开销) constexpr double compile_time_pi = 3.1415926535; double area = compile_time_pi * radius * radius; // 🔄 编译时代入// 运行期计算(有运行时开销) double runtime_pi = get_pi_from_file(); // 🔄 需要文件I/O double area = runtime_pi * radius * radius; // 🔄 运行时计算
错误检测时机
cpp
// 编译期错误(立即发现) constexpr int value = "hello"; // ❌ 编译错误:类型不匹配// 运行期错误(可能很久才发现) int divisor = get_user_input(); int result = 100 / divisor; // ❌ 可能运行时除零错误
实际开发中的例子
游戏开发
cpp
// 编译期确定(游戏配置) constexpr int MAX_PLAYERS = 4; // 🔄 编译时确定 constexpr int SCREEN_WIDTH = 1920; // 🔄 编译时确定// 运行期确定(游戏运行时) int current_players; // 🔄 运行时变化 Player players[MAX_PLAYERS]; // 🔄 编译时确定数组大小
数学计算
cpp
// 编译期计算(常数计算) constexpr double PI = 3.141592653589793; constexpr double DEG_TO_RAD = PI / 180.0; // 🔄 编译时计算// 运行期计算(动态数据) double calculate_angle(double x, double y) {return std::atan2(y, x) * 180.0 / PI; // 🔄 运行时计算 }
总结
特性 | 编译期(Compile Time) | 运行期(Run Time) |
---|---|---|
时间 | 程序运行前 | 程序运行中 |
执行者 | 编译器 | CPU |
工作内容 | 语法检查、类型检查、优化 | 实际计算、I/O操作 |
错误类型 | 编译错误 | 运行时错误 |
输入来源 | 源代码 | 用户输入、文件等 |
确定性 | 确定性的 | 可能不确定 |
简单记忆:
编译期:编译器处理代码的阶段("纸上谈兵")
运行期:程序实际执行的阶段("真枪实弹")
理解这个区别对于写出高效、安全的C++代码非常重要