【问题标题】:#define syntax with L identifier#define 带有 L 标识符的语法
【发布时间】:2012-04-20 13:17:49
【问题描述】:
#define CONST_FILENAME "okay.dat"
LPCWSTR lpFilename=L CONST_FILENAME; //obviously doesn't work

基本上,我如何获得相当于:

LPCWSTR lpFilename=L"okay.dat";

使用#define?

【问题讨论】:

  • 对 VC++ 不太熟悉,但我相信 _T(CONST_FILENAME) 应该可以。如 LPCWSTR fn = _T(CONST_FILENAME);
  • 错误:未找到“_T”标识符。是的,我仍然包含 。我知道我在这里做错了。
  • 快速谷歌显示它是在 tchar.h 中定义的
  • 不幸的是,它也会把你束缚在 Windows 上。我相信 _T 和 TEXT 不是标准的。我一直在谷歌搜索,但似乎无法弄清楚如何以符合标准的方式进行操作。
  • @corbin: _T 和其他宏一样。如果未定义,请自行定义。现在符合标准。

标签: c++ c winapi c-preprocessor widechar


【解决方案1】:
#define GLUE(x,y) x##y
#define W(x) GLUE(L,x)

#define CONST_FILENAME "okay.dat"

int main() {
    const wchar_t* lpFilename = W(CONST_FILENAME);
    const wchar_t* lpFilename = W("okay.dat");
    wchar_t one_character = W('?');
}

编译证明http://ideone.com/2EzB6。这正是 Microsoft 的 _T 宏的工作原理,除了我无条件地定义它,因此即使不在 MSVC“Unicode”构建中,您也可以使用它来获取宽字符串。至于为什么需要 GLUE 宏,我从来没有听到过对我有意义的解释,但是没有它,宏就不会扩展,所以它是必需的。这里好像有详细信息:What are the applications of the ## preprocessor operator and gotchas to consider?

【讨论】:

    【解决方案2】:

    #define CONST_FILENAME L"okay.dat"

    【讨论】:

    • 但是如果我想在 ASCII 上下文中使用 CONST_FILENAME 怎么办?比如char *something=CONST_FILENAME?
    • 宽字符串是一种不同的类型。将其复制到适合您平台的宽字符类型。 POSIX 有 wchar_t。 wchar_t s[99];wcscpy(s,CONST_FILENAME);不确定 Windows,也许是 WCHAR?还可以使用库或特定于实现的转换函数将文件名转换为 char 并冒丢失某些字符/文件未找到错误的风险。
    【解决方案3】:

    但是如果我想在 ASCII 上下文中使用 CONST_FILENAME 怎么办?如:

    char *something = CONST_FILENAME;
    

    L"okay.dat" 中的 L 不能与 " 用空格分隔。宽字符字符串是单个标记,您不能直接“将L 添加到它”。但是,您可以进行字符串连接:

    #include <wchar.h>
    
    #define A_STRING "xyz.txt"
    
    /* MMT - Magical Mystery Tour */
    #define MMT(x) L"" x
    
    char a[] = A_STRING;
    wchar_t w[] = MMT(A_STRING);
    

    狡猾,但 GCC 可以接受。这很好,因为标准也是如此。这是来自 C99 标准:

    §6.4.5 字符串文字

    ¶4 在翻译阶段 6,由任何序列指定的多字节字符序列 相邻字符和宽字符串文字标记连接成单个多字节 字符序列。如果任何标记是宽字符串文字标记,则结果 多字节字符序列被视为宽字符串文字;否则,它被视为 字符串文字。


    测试代码:

    #include <assert.h>
    #include <stdio.h>
    #include <string.h>
    #include <wchar.h>
    
    #define A_STRING "xyz.txt"
    
    /* MMT - Magical Mystery Tour */
    #define MMT(x) L"" x
    
    static char a[] = A_STRING;
    static wchar_t w[] = MMT(A_STRING);
    
    int main(void)
    {
        int len1 = wcslen(w);
        int len2 = sizeof(w) / sizeof(w[0]) - 1;
        int len3 = strlen(a);
        int len4 = sizeof(a) / sizeof(a[0]) - 1;
    
        assert(len1 == len2);
        assert(len3 == len4);
        assert(len1 == len3);
        printf("sizeof(a) = %zu; sizeof(w) = %zu\n", sizeof(a), sizeof(w));
    
        for (int i = 0; i < len1; i++)
            printf("%d = %d\n", i, (int)w[i]);
    
        for (int i = 0; i < len1; i++)
            printf("%d = %d\n", i, (int)a[i]);
    
        return(0);
    }
    

    编译:

    gcc -O3 -g -Wall -Wextra -std=c99  xx.c -o xx  
    

    示例输出:

    sizeof(a) = 8; sizeof(w) = 32
    0 = 120
    1 = 121
    2 = 122
    3 = 46
    4 = 116
    5 = 120
    6 = 116
    0 = 120
    1 = 121
    2 = 122
    3 = 46
    4 = 116
    5 = 120
    6 = 116
    

    测试平台

    MacOS X 10.7.3 (Lion)。 64位编译。

    i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1(基于 Apple Inc. build 5658)(LLVM build 2335.15.00)

    【讨论】:

    • 刚刚在 Visual Studio 2008 和 2010 中尝试过。在这两种情况下,我都会遇到编译器错误:"error C2308: concatenating mismatched strings concatenating wide "" with narrow "xyz.txt""。基于 OP 对LPCWSTR typedef 的使用,我推断他们使用的是 Windows(很可能是 Visual Studio)。由于标准明确允许这种语法,这是 MSVC 中的一个错误。也许这是一个已知问题。
    • “问题”(或者可能是“原因”)可能是 MSVC 没有声称符合 C99 标准。我不记得 C89 对连接宽字符串和非宽字符串有什么看法。
    • 噢!我不知何故错过了 C99 位。
    • @JonathanLeffler:C89/C90 标准明确表示行为未定义。 (因此 MSVC 可以实现 C99 语义而不违反 C99 标准。)
    • @KeithThompson:您的意思是“可以在不违反 C89 标准的情况下实现 C99 语义”吗?如果是这样,我同意他们可以,但从 André 的评论看来,微软选择不实现 C99 语义,而是选择生成错误。可惜。甚至令人讨厌。 (实际上,MS 在很大程度上没有实现 C99 使得编写必须在 Windows 和 Unix 上运行的现代代码相当困难。我发现我背负着 22 年的技术而不是 13 年的技术,这令人沮丧。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多