从单个定义创建字符串和宽字符串文字

Create string and wide string literals from a single definition

有时需要为 char *wchar_t * 类型创建具有相同值的字符串文字(例如,在 Windows 中开发时)。一个简单的方法是将定义写两次:

const char *my_string = "Hello World";
const wchar_t *my_wide_string = L"Hello World";

问题是,如果我们需要更改字符串,而不是只更改一个地方,则两行都需要更新,这通常会导致拼写错误和错误。理想情况下,文字应该只出现一次,并且两个变量都由它填充。

我们可以定义 char 变量并在运行时将其转换为 wchar_t 版本。但是,最好避免运行时成本,因为文字在编译时已经可用。

我想使用标记粘贴运算符,但无法使其工作,因为它只接受另一个字符串文字:

#define my_string "Hello World"
#define make_wide(str) L##str
#define my_wide_string make_wide(my_string)  // expand to Lmy_string instead of L"Hello World"

我不确定是否可以使用 constexpr 让它工作?

您不太可能希望两个版本都采用适当的设计。无论如何,这两种类型(charwchar_t)不兼容(8/16位)所以你不能在编译级别做到这一点。

设计一个 class 使用 wchar_t 并仅在必要时转换为 char。为此,您使用 WideCharToMultiByte

将整个应用程序设计为仅使用宽字符,并且在序列化时仅使用 UTF-8 格式。

您只需要另一个宏,以便在粘贴之前扩展宏的参数:

#include <wchar.h>

#define my_string "Hello World"

#define WidenHelper(x)  L##x
#define Widen(x)        WidenHelper(x)

const char *plain   = my_string;
const wchar_t *wide = Widen(my_string);

因为你在 Windows,你可以在 crtdefs.h 中使用 _STR2WSTR,当你 #include <windows.h> 时它会被包含在内。还有 __FILEW____FUNCTIONW__ 由普通字符串变体制成,例如

/* error reporting helpers */
#define __STR2WSTR(str)    L##str
#define _STR2WSTR(str)     __STR2WSTR(str)

#define __FILEW__          _STR2WSTR(__FILE__)
#define __FUNCTIONW__      _STR2WSTR(__FUNCTION__)

更新:

后来的 CRT 版本将其更改为 _CRT_WIDE

#define _CRT_WIDE_(s) L ## s
#define _CRT_WIDE(s) _CRT_WIDE_(s)