使用L标识符的#define语法

3
#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); 这样。 - Corbin
错误:找不到'_T'标识符。是的,我已经包括了<cstdio>和<cstdlib>,但仍然出错了。我知道我在这里做错了什么。 - IND000
1
快速谷歌搜索显示它在tchar.h中定义。 - Corbin
1
不幸的是,我相信它也会将您限制在Windows上。我已经谷歌了一段时间,但似乎无法找出如何以符合标准的方式进行_T和TEXT的方法。 - Corbin
@corbin:_T就像其他宏一样。如果没有定义,你可以自己定义它。现在它符合标准了。 - Mooing Duck
3个回答

5
#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 宏,我从未听过任何让我感到有道理的解释,但没有它,宏就无法扩展,因此它是必需的。这里似乎有细节:## 预处理器运算符的应用和需要考虑的陷阱是什么?


3

#define CONST_FILENAME L"okay.dat"


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

2

But what if I want to use CONST_FILENAME in an ASCII context [too]? Such as:

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(狮子山)64位编译。

i686-apple-darwin11-llvm-gcc-4.2(GCC)4.2.1(基于Apple Inc.构建的5658版本)(LLVM构建2335.15.00)


@JonathanLeffler:C89/C90标准明确规定该行为未定义。(因此,MSVC可以实现C99语义而不违反C99标准。) - Keith Thompson
@KeithThompson:你是说“可以在不违反C89标准的情况下实现C99语义”吗?如果是这样,我同意他们可以这样做,但从André的评论中看来,微软选择不实现C99语义,而是选择生成错误。真遗憾,甚至很烦人。(实际上,微软大部分没有实现C99,这使得编写必须在Windows和Unix上运行的现代代码变得非常困难。我觉得很沮丧,因为我被束缚在22年前的技术上,而不是13年前的技术上。) - Jonathan Leffler
@JonathanLeffler:是的,那就是我所说的意思。(你不喜欢那些只有一个字符的笔误却完全改变了你想要表达的意思吗?) - Keith Thompson
为什么不让MMT像_T一样工作,这样它就可以在各种平台上使用,并且支持字符?它只是像其他宏一样的东西。 - Mooing Duck
@MooingDuck:由于我不知道_T的作用,所以我也不知道要做什么才能让MMT实现_T的功能。为什么不将这个作为你自己的答案提交呢? - Jonathan Leffler
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接