You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QueryPerformanceFrequency在32/64位GCC下异常的原因及优化方案

QueryPerformanceCounter计时器在64位GCC下计时为0的问题分析与解决

问题根源:构造函数命名错误

你的代码存在致命C++语法错误:类定义为class qlTime,但编写的构造函数却是qTimeClass()——这不是构造函数,只是普通成员函数。编译器会自动为qlTime生成默认构造函数,导致:

  • 全局对象qTime初始化时,qFreq作为全局变量被默认初始化为0.0
  • 后续计算qMSec和qSec时,均是除以0,得到的NaN/无穷大强制转换为unsigned long int后变为0,这就是计时全为0的直接原因

32位GCC可能因宽松编译检查或测试版本中构造函数命名正确,才未暴露问题;而64位GCC严格遵循标准,直接触发了错误。你遇到的情况并非QueryPerformanceFrequency调用失败,而是构造逻辑根本没执行,频率值从未被正确设置。

临时修复的逻辑隐患

你在Update中通过qMSec==0触发重新获取频率,本质是利用初始值特性补做了一次初始化,但存在问题:

  • 若程序运行极长时间(超出unsigned long范围),qMSec可能溢出回到0,导致不必要的重复获取频率
  • 未检查QueryPerformanceFrequency的返回值,无法处理极端异常场景

更优解决方案

1. 修正构造函数命名,添加返回值检查

先修复构造函数命名错误,同时添加返回值检查确保频率获取成功:

class qlTime{
public:
    LARGE_INTEGER qTime_Start, qTime_End;
    unsigned long int qSec, qMSec;
    double qFreq;

    // 构造函数名与类名保持一致
    qlTime(){
        qSec = 0;
        qMSec = 0;
        qFreq = 0.0;

        LARGE_INTEGER freq;
        if (QueryPerformanceFrequency(&freq)) {
            qFreq = static_cast<double>(freq.QuadPart);
        } else {
            // 极端场景降级处理,使用默认1MHz频率
            qFreq = 1000000.0;
        }
        QueryPerformanceCounter(&qTime_Start);
    }

    void qReset(){
        QueryPerformanceCounter(&qTime_Start);
    }

    void Update(){
        QueryPerformanceCounter(&qTime_End);
        const double elapsedTicks = qTime_End.QuadPart - qTime_Start.QuadPart;
        qMSec = static_cast<unsigned long>(elapsedTicks * 1000.0 / qFreq);
        qSec = static_cast<unsigned long>(elapsedTicks / qFreq);
    }
} qTime;

2. 延迟初始化(懒加载)

若担心全局对象初始化时机问题(如程序启动时QueryPerformanceFrequency无法正常调用),可将频率获取延迟到第一次调用Update时:

class qlTime{
public:
    LARGE_INTEGER qTime_Start, qTime_End;
    unsigned long int qSec, qMSec;
    double qFreq;
    bool isFreqInitialized;

    qlTime() : qSec(0), qMSec(0), qFreq(0.0), isFreqInitialized(false) {
        // 先记录起始时间,频率等第一次Update再初始化
        QueryPerformanceCounter(&qTime_Start);
    }

    void qReset(){
        QueryPerformanceCounter(&qTime_Start);
    }

    void Update(){
        if (!isFreqInitialized) {
            LARGE_INTEGER freq;
            if (QueryPerformanceFrequency(&freq)) {
                qFreq = static_cast<double>(freq.QuadPart);
            } else {
                qFreq = 1000000.0;
            }
            isFreqInitialized = true;
        }

        QueryPerformanceCounter(&qTime_End);
        const double elapsedTicks = qTime_End.QuadPart - qTime_Start.QuadPart;
        qMSec = static_cast<unsigned long>(elapsedTicks * 1000.0 / qFreq);
        qSec = static_cast<unsigned long>(elapsedTicks / qFreq);
    }
} qTime;

3. 局部静态变量封装(线程安全,推荐)

若无需全局对象,可将计时器封装为函数内的局部静态变量,确保初始化时机正确(C++11及以上线程安全):

qlTime& GetGlobalTimer() {
    static qlTime timer; // 第一次调用时初始化
    return timer;
}

额外注意事项

  • 编译时启用C++11及以上标准,避免线程安全问题
  • unsigned long int通常为32位,最大仅支持约71分钟计时,若需更长时间建议使用uint64_t类型
  • 计算时优先做乘法再除法,减少精度损失(如(ticks * 1000) / freq比ticks / freq * 1000精度更高)

内容的提问来源于stack exchange,提问作者Tobi PL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:12:52