3
#define CONST_FILENAME "okay.dat"
LPCWSTR lpFilename=L CONST_FILENAME; //obviously doesn't work

Basically, how do I get the equivalent of:

LPCWSTR lpFilename=L"okay.dat";

using #define?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
IND000
  • 29
  • 3
  • Not overly familiar with VC++, but I believe _T(CONST_FILENAME) should work. As in LPCWSTR fn = _T(CONST_FILENAME); – Corbin Apr 07 '12 at 04:11
  • Error: '_T' identifier not found. Yes, I included and and still. I know I'm doing something wrong here. – IND000 Apr 07 '12 at 04:17
  • 1
    A quick google shows that it's defined in tchar.h – Corbin Apr 07 '12 at 04:18
  • 1
    Unfortunately it will also tie you down to Windows I believe that _T and TEXT are not standard. I've been googling for a bit, but can't seem to figure out how to do it in a standard compliant way. – Corbin Apr 07 '12 at 04:27
  • @corbin: _T is a macro like any other. if it's not defined, define it yourself. Now its standard compliant. – Mooing Duck Sep 06 '12 at 08:21

3 Answers3

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('?');
}

Proof of compilation at http://ideone.com/2EzB6. This is exactly how the Microsoft's _T macro works, except I unconditionally define it, so you can use it to get wide strings even when not in a MSVC "Unicode" build. As to why the GLUE macro is required, I've never heard an explanation that made sense to me, but without it the macro won't expand, so it's required. It looks like there's details here: What are the applications of the ## preprocessor operator and gotchas to consider?

Community
  • 1
  • 1
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
3

#define CONST_FILENAME L"okay.dat"

Retired Ninja
  • 4,785
  • 3
  • 25
  • 35
  • But what if I want to use CONST_FILENAME in an ASCII context? Such as `char *something=CONST_FILENAME`? – IND000 Apr 07 '12 at 04:13
  • Wide strings are a different type. Copy it to a wide character type for your platform. POSIX has wchar_t. wchar_t s[99];wcscpy(s,CONST_FILENAME); Not sure about Windows, maybe WCHAR? Can also use a library or implementation-specific conversion function to convert the file name to char and risk missing some characters/file not found errors. – hellork Apr 07 '12 at 05:07
2

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

char *something = CONST_FILENAME;

The L in L"okay.dat" cannot be separated from the " by white space. The wide-char string is a single token, and you can't directly 'add the L to it'. But, you can do string concatenation:

#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);

Devious, but GCC is OK with it. That's just well, because the standard is too. This is from the C99 standard:

§6.4.5 String Literals

¶4 In translation phase 6, the multibyte character sequences specified by any sequence of adjacent character and wide string literal tokens are concatenated into a single multibyte character sequence. If any of the tokens are wide string literal tokens, the resulting multibyte character sequence is treated as a wide string literal; otherwise, it is treated as a character string literal.


Test code:

#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);
}

Compilation:

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

Example output:

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

Test platform

MacOS X 10.7.3 (Lion). 64-bit compilation.

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

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Just tried this with Visual Studio 2008 and 2010. In both cases I get compiler errors: `"error C2308: concatenating mismatched strings concatenating wide "" with narrow "xyz.txt""`. Based on OP's use of the `LPCWSTR` typedef, I would infer they're using Windows (and most likely Visual Studio). Since the standard clearly allows this syntax, this is a bug in MSVC. Maybe this is a known issue. – André Caron Apr 07 '12 at 05:35
  • The 'problem' (or maybe 'reason') might be that MSVC does not claim compliance with the C99 standard. I don't remember what C89 had to say about concatenating wide and non-wide strings. – Jonathan Leffler Apr 07 '12 at 06:01
  • Doh! I somehow missed the C99 bit. – André Caron Apr 07 '12 at 06:16
  • @JonathanLeffler: The C89/C90 standard explicitly says the behavior is undefined. (So MSVC *could* implement the C99 semantics without violating the C99 standard.) – Keith Thompson Apr 07 '12 at 07:56
  • @KeithThompson: Did you mean 'could implement C99 semantics without violating the C**8**9 standard'? If so, I'd agree that they could, but it seems from André's comment that Microsoft has chosen not to implement C99 semantics and has opted for generating an error instead. A pity. A nuisance, even. (Actually, MS not implementing C99 for the most part makes writing modern code that has to run on Windows and Unix rather hard. I find it frustrating that I'm saddled with 22-year technology instead of just 13-year old technology.) – Jonathan Leffler Apr 07 '12 at 08:14
  • @JonathanLeffler: Yes, that's what I meant. (Don't you just *love* one-character typos that completely change the meaning of what you're trying to say?) – Keith Thompson Apr 07 '12 at 08:32
  • Why not just make MMT do what _T does, so it works portably, and with characters? its a macro like any other. – Mooing Duck Sep 06 '12 at 08:25
  • @MooingDuck: Since I don't know what `_T` does, I don't know what would be required to make MMT do what `_T` does. Why don't you submit that as your own answer? – Jonathan Leffler Sep 06 '12 at 13:05