MALOUDA-PSA 2025-05-17 19:39 采纳率: 85.6%
浏览 23

vs控制台输出的问题

在VS2019的 debug 模式执行:


void AttachConsoleWindow() {
    AllocConsole();
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    FILE* fp;
    freopen_s(&fp, "CONOUT$", "w", stdout);
    SetConsoleTitle(L"Application Console");
}
。。。 。。。
std::cerr << "Lua error: " << lua_tostring(L, -1) << std::endl;
                std::cerr.flush();

std::cerr 仍然没看到输出, 可是如果printf 在控制台可以看到

  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-05-17 19:40
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    从你的描述来看,问题的核心在于 std::cerr 的输出没有显示在控制台上,而 printf 却可以正常输出。这种情况通常与标准流的重定向或缓冲机制有关。以下是对问题的分析以及解决方案。


    问题分析

    1. freopen_s 的影响

      • 你在调用 freopen_s 时将 stdoutstderr 都重定向到了 CONOUT$,这可能导致 std::cerr 的输出被重定向到控制台,但其行为可能受到缓冲的影响。
      • std::cerr 默认是未缓冲的(unbuffered),但某些情况下,它可能会因为重定向而表现出类似缓冲的行为。
    2. 控制台窗口的初始化顺序

      • AllocConsole() 创建了一个新的控制台窗口,但在调用 SetConsoleTitle 之前,可能需要确保 stdoutstderr 已正确初始化。
    3. std::cerr 的刷新机制

      • 调用 std::cerr.flush() 是正确的做法,但如果缓冲机制没有正确配置,输出可能不会立即显示。
    4. printfstd::cerr 的区别

      • printf 直接写入 stdout,而 std::cerr 是通过 C++ 标准库实现的。两者的行为可能因底层流的配置不同而表现不一致。

    解决方案

    以下是逐步解决问题的方案:

    1. 确保 stdoutstderr 正确重定向

    你可以尝试在调用 freopen_s 后,显式地刷新流,以确保输出立即可见。

    void AttachConsoleWindow() {
        AllocConsole();
        HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hConsole == INVALID_HANDLE_VALUE) {
            // 错误处理
            return;
        }
    
        FILE* fp;
        // 将 stdout 和 stderr 重定向到控制台
        freopen_s(&fp, "CONOUT$", "w", stdout);
        freopen_s(&fp, "CONOUT$", "w", stderr);
    
        // 刷新流以确保输出立即可见
        fflush(stdout);
        fflush(stderr);
    
        SetConsoleTitle(L"Application Console");
    }
    

    2. 使用 _setmode 设置流模式

    在 Windows 上,std::coutstd::cerr 的行为可能受控制台编码的影响。使用 _setmode 设置流为 UTF-8 或 ANSI 编码,可以避免编码问题。

    #include <fcntl.h>
    #include <io.h>
    
    void AttachConsoleWindow() {
        AllocConsole();
        HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hConsole == INVALID_HANDLE_VALUE) {
            // 错误处理
            return;
        }
    
        // 设置 stdout 和 stderr 为 UTF-8 模式
        _setmode(_fileno(stdout), _O_U8TEXT);
        _setmode(_fileno(stderr), _O_U8TEXT);
    
        FILE* fp;
        // 将 stdout 和 stderr 重定向到控制台
        freopen_s(&fp, "CONOUT$", "w", stdout);
        freopen_s(&fp, "CONOUT$", "w", stderr);
    
        // 刷新流以确保输出立即可见
        fflush(stdout);
        fflush(stderr);
    
        SetConsoleTitle(L"Application Console");
    }
    

    3. 检查是否需要手动刷新

    如果你已经设置了 freopen_s_setmode,但仍然看不到输出,可以尝试手动刷新流。例如,在输出后立即调用 fflush

    std::cerr << "Lua error: " << lua_tostring(L, -1) << std::endl;
    fflush(stderr); // 手动刷新 stderr
    

    4. 使用 std::wcerr 替代 std::cerr

    如果问题与字符编码相关,可以尝试使用宽字符流 std::wcerr

    std::wcerr << L"Lua error: " << lua_tostring(L, -1) << std::endl;
    fflush(stderr); // 手动刷新 stderr
    

    完整示例代码

    以下是综合上述解决方案的完整代码:

    #include <iostream>
    #include <cstdio>
    #include <windows.h>
    #include <io.h>
    #include <fcntl.h>
    
    void AttachConsoleWindow() {
        AllocConsole();
        HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hConsole == INVALID_HANDLE_VALUE) {
            // 错误处理
            return;
        }
    
        // 设置 stdout 和 stderr 为 UTF-8 模式
        _setmode(_fileno(stdout), _O_U8TEXT);
        _setmode(_fileno(stderr), _O_U8TEXT);
    
        FILE* fp;
        // 将 stdout 和 stderr 重定向到控制台
        freopen_s(&fp, "CONOUT$", "w", stdout);
        freopen_s(&fp, "CONOUT$", "w", stderr);
    
        // 刷新流以确保输出立即可见
        fflush(stdout);
        fflush(stderr);
    
        SetConsoleTitle(L"Application Console");
    }
    
    int main() {
        AttachConsoleWindow();
    
        // 示例输出
        std::cerr << "This is a test message from std::cerr." << std::endl;
        std::wcerr << L"This is a test message from std::wcerr." << std::endl;
    
        return 0;
    }
    

    总结

    通过以上步骤,你应该能够解决 std::cerr 输出不显示的问题。关键点包括:

    1. 确保 stdoutstderr 正确重定向。
    2. 使用 _setmode 设置流的编码模式。
    3. 手动刷新流以确保输出立即可见。
    4. 如果问题仍未解决,可以尝试使用宽字符流 std::wcerr

    如果仍有疑问,请提供更多上下文信息,以便进一步诊断问题。

    评论

报告相同问题?

问题事件

  • 创建了问题 5月17日