当 TCHAR 可以映射到 char 或 wchar_t 时,将 TCHAR 字符串打印到 std::ostream

Print TCHAR string to std::ostream when TCHAR can map to either char or wchar_t

提问人:ddevienne 提问时间:8/10/2023 最后编辑:ddevienne 更新时间:8/10/2023 访问量:36

问:

我在不同的可执行文件中重用相同的完全相同的源文件(用于命令行解析)。我不使用库,而是直接在每个 exe 中构建相同的源代码。

最近,我添加了一个选项来列出可执行文件使用的所有共享库。这在我测试的 exe 中工作正常,但是当我在不同的 exe 上尝试时,它编译但工作不正常,打印地址而不是共享库的路径。我(隐约)知道 TCHAR。不知何故,这两个具有不同依赖项(通过 CMake 构建引入)的 ex 最终具有不同的 TCHAR 类型 ( vs )。两个前任都接受了,但第一个是打电话,第二个是打电话,因此打印地址。charwchat_tos << me32.szExePathop<<(..., const char*)op<<(..., const void*)

好的,我想,我将只使用编译时 if (即 ) 因为我在 C++ 17 中,并在案例中使用原样,并明确地将其从 转换为 else。下面的代码修复了第二个 exe,因此它打印了路径(而不是地址)。但后来它打破了第一个前任!!if constexprme32.szExePathcharwchar_tchar

1>...\CliContext.cpp(1703,81): error C2664: 'errno_t wcstombs_s(size_t *,char *,size_t,const wchar_t *,size_t)': cannot convert argument 4 from 'char [260]' to 'const wchar_t *'
1>...\CliContext.cpp(1703,55): message : Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\ucrt\stdlib.h(999,26): message : see declaration of 'wcstombs_s'

这对我来说毫无意义,因为第一个 exe 不应该编译两个分支。毕竟,它不能有两个相同的值,不是吗?if constexprsizeof(*me32.szExePath)

我显然错过了什么......有人可以帮忙吗?

有没有办法编写此代码,使其在两种 TCHAR 情况下都有效,用于打印到 ?std::ostream

PS:我之前尝试过另一个编译时if,同样失败了。if constexpr (std::is_same_v<wchar_t, *me32.szExePath>)

PPS:这些是跨平台的 exe。我没有展示 linux 方面。我确实想使用而不是其他东西来打印std::ostream

#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>

static void sharedLibraries(std::ostream& os) {
    auto dwPID = GetCurrentProcessId();
    HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
    if (hModuleSnap == INVALID_HANDLE_VALUE) {
        raise("CreateToolhelp32Snapshot (of modules)");
    }
    using Handle_uptr = std::unique_ptr<void, decltype(&CloseHandle)>;
    Handle_uptr h(hModuleSnap, &CloseHandle);

    MODULEENTRY32 me32;
    me32.dwSize = sizeof(me32);
    if (!Module32First(hModuleSnap, &me32)) {
        raise("Module32First");
    }
    do {
        assert(me32.th32ProcessID == dwPID);
        if constexpr (sizeof(*me32.szExePath) == 1) {
            os << me32.szExePath << std::endl;
        }
        if constexpr (sizeof(*me32.szExePath) == 2) {
            size_t size = 0; char path[260*4];
            wcstombs_s(&size, path, sizeof(path), me32.szExePath, sizeof(path)-1);
            os << path << std::endl;
        }
    } while (Module32Next(hModuleSnap, &me32));
}
Windows C++17 查尔 IF-constExpr

评论

0赞 Mark Ransom 8/10/2023
您可能应该设置为,以便它填充 null。path={}
0赞 Ted Lyngmo 8/10/2023
raise("...");- 这是 Windows 特定的重载吗? 需要一个参数。 Tries 将类型进行比较。这永远行不通。std::raiseintstd::is_same_v<wchar_t, *me32.szExePath>
0赞 Ted Lyngmo 8/10/2023
你不能只用 s 什么时候吗?std::wostreamstd::is_same_v<TCHAR, wchar_t>
0赞 ddevienne 8/10/2023
@MarkRansom当然。虽然我相信这里无关紧要,因为会写并 null 终止它。wcstombs_c
0赞 ddevienne 8/10/2023
@TedLyngmo 好点子。我应该使用.谢谢。decltype

答:

0赞 ddevienne 8/10/2023 #1

使用它对我有用:

#ifdef UNICODE
        size_t size = 0; char path[260*4];
        wcstombs_s(&size, path, sizeof(path), me32.szExePath, sizeof(path)-1);
        os << path << std::endl;
#else
        os << me32.szExePath << std::endl;
#endif

不过,我仍然想知道为什么会失败。FWIW。if constexpr

评论

1赞 Luke 8/10/2023
en.cppreference.com/w/cpp/language/if“在模板之外,会完全检查丢弃的语句。如果 constexpr 不能替代 #if 预处理指令”
0赞 ddevienne 8/10/2023
@Luke 啊!这就是我缺少的部分。谢谢。以前一定在模板中使用过它,并且错误地认为会转移到常规代码中。