编译时检查vs运行时检查

一、编译时检查vs运行时检查

特性编译时检查运行时检查
发生时间程序运行之前(编译阶段)程序运行期间
检查内容语法、类型、访问权限、函数签名等数组越界、空指针、除零、文件不存在、网络中断等
执行者编译器(如 GCC, Javac, TypeScript Compiler)程序本身或运行时环境(如 JVM, CLR)
错误类型编译错误(Compilation Error)运行时异常/错误(Runtime Exception/Error)
对程序的影响程序无法生成可执行文件,必须修复错误才能运行。程序已经运行,可能导致崩溃、异常或未定义行为。
性能增加编译时间,但不影响运行时性能。增加运行时的开销,因为需要在代码执行时进行判断。
确定性高。只要代码不变,检查结果就是确定的。低。依赖于运行时的输入、环境状态等。
主要目标保证代码的正确性结构性,提前发现大量低级错误。保证程序在不确定环境下的健壮性容错能力
典型语言Java, C#, C++, TypeScript, Go(静态类型语言)JavaScript, Python, Ruby(动态类型语言),以及所有语言的运行时校验

二、举例说明:

2.1 编译时检查

2.1.1 语法错误

#include <iostream>
using namespace std;

int main() {
    int x = 5
    // 编译错误:缺少分号
    // error: expected ';' after expression
    return 0;
}

2.1.2 类型错误

#include <iostream>
#include <string>
using namespace std;

int main() {
    string name = "Alice";
    int length = name.length(); // 正确
    
    // 编译错误:类型不匹配
    string result = 42; // error: cannot convert 'int' to 'std::string'
    
    return 0;
}

2.1.3 函数签名错误

#include <iostream>
using namespace std;

void printNumber(int x) {
    cout << "Number: " << x << endl;
}

int main() {
    printNumber(10);     // 正确
    printNumber("hello"); // 编译错误:参数类型不匹配
    // error: could not convert '("hello")' from 'const char*' to 'int'
    
    return 0;
}

2.1.4 模板实例化检查

#include <iostream>
using namespace std;

template<typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    cout << add(5, 3) << endl;    // 正确:int + int
    cout << add(2.5, 3.7) << endl; // 正确:double + double
    
    // 编译错误:没有匹配的运算符
    struct Point { int x, y; };
    Point p1{1,2}, p2{3,4};
    // auto result = add(p1, p2); // error: no match for 'operator+'
    
    return 0;
}

2.1.5  constexptr检查

#include <iostream>
using namespace std;

constexpr int factorial(int n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

int main() {
    // 编译时计算
    constexpr int result = factorial(5); // 在编译时计算 5!
    cout << "5! = " << result << endl;   // 输出 120
    
    // 编译错误:constexpr 函数参数必须在编译时可知
    int n = 5;
    // constexpr int bad = factorial(n); // error: 'n' is not a constant expression
    
    return 0;
}

2.2 运行时检查

2.2.1 数组越界

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};
    
    // 使用 at() 方法进行运行时边界检查
    try {
        cout << numbers.at(2) << endl;  // 正确:输出 3
        cout << numbers.at(10) << endl; // 运行时异常:越界访问
    }
    catch (const out_of_range& e) {
        cout << "捕获到异常: " << e.what() << endl;
    }
    
    // 使用 [] 运算符(通常无边界检查)
    cout << numbers[2] << endl;  // 正确:输出 3
    cout << numbers[10] << endl; // 未定义行为!可能崩溃或输出垃圾值
    
    return 0;
}

2.2.2 动态类型转换

#include <iostream>
using namespace std;

class Animal {
public:
    virtual ~Animal() = default;
};

class Dog : public Animal {
public:
    void bark() { cout << "Woof!" << endl; }
};

class Cat : public Animal {
public:
    void meow() { cout << "Meow!" << endl; }
};

int main() {
    Animal* animal1 = new Dog();
    Animal* animal2 = new Cat();
    
    // 运行时类型检查:dynamic_cast
    if (Dog* dog = dynamic_cast<Dog*>(animal1)) {
        dog->bark(); // 会执行:animal1 确实是 Dog
    }
    
    if (Dog* dog = dynamic_cast<Dog*>(animal2)) {
        dog->bark(); // 不会执行:animal2 是 Cat,不是 Dog
    } else {
        cout << "animal2 不是 Dog 类型" << endl;
    }
    
    delete animal1;
    delete animal2;
    return 0;
}

2.2.3 除零检查

#include <iostream>
#include <stdexcept>
using namespace std;

double divide(int a, int b) {
    if (b == 0) {
        throw runtime_error("除零错误");
    }
    return static_cast<double>(a) / b;
}

int main() {
    try {
        cout << divide(10, 2) << endl;  // 正确:输出 5
        cout << divide(10, 0) << endl;  // 运行时异常
    }
    catch (const runtime_error& e) {
        cout << "捕获到异常: " << e.what() << endl;
    }
    
    return 0;
}

2.2.4 文件操作检查

#include <iostream>
#include <fstream>
using namespace std;

int main() {
    ifstream file("不存在的文件.txt");
    
    // 运行时检查文件是否成功打开
    if (!file.is_open()) {
        cout << "无法打开文件!" << endl;
        return 1;
    }
    
    string content;
    while (getline(file, content)) {
        cout << content << endl;
    }
    
    // 检查文件读取状态
    if (file.bad()) {
        cout << "文件读取过程中发生错误" << endl;
    }
    
    file.close();
    return 0;
}

2.2.5 智能指针为空检查

#include <iostream>
#include <memory>
using namespace std;

class Resource {
public:
    void use() { cout << "使用资源" << endl; }
};

int main() {
    unique_ptr<Resource> ptr1 = make_unique<Resource>();
    unique_ptr<Resource> ptr2 = nullptr;
    
    // 运行时检查指针是否为空
    if (ptr1) {
        ptr1->use(); // 会执行
    }
    
    if (ptr2) {
        ptr2->use(); // 不会执行
    } else {
        cout << "ptr2 是空指针" << endl;
    }
    
    return 0;
}

三、总结

在 C++ 中,良好的编程实践是:

  • 尽可能在编译时发现问题(使用强类型、static_assert 等)

  • 对不可避免的运行时错误进行适当处理(异常处理、错误码等)

  • 使用工具如 ASan、UBSan 等来检测未定义行为

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10710

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值