Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I concatenate wide string literals with PRId32, PRIu64, etc.?

Suppose I need to print a formatted string with an int32_t using the printf format specifier from <inttypes.h>.

int32_t i = 0;
printf("%" PRId32 "\n", i);

If I try to do the same with wide characters in Visual C++ 2013, it fails:

#define W_(val) L ## val
#define W(val) W_(val)
wprintf(L"%" W(PRId32) L"\n", i);

error C2308: concatenating mismatched strings

How do I concatenate wide string literals with format conversion specifier macros?

like image 956
Timothy003 Avatar asked Feb 14 '14 20:02

Timothy003


2 Answers

The problem is twofold. First, as noted in rici's answer, C99 and C++11 both added support for concatenating narrow string literals and wide string literals together, so you should not need to widen the narrow literal by prepending the L. Visual C++ does not yet support this feature for either C or C++.

Because the compiler does not yet support this feature, we should in the libraries make it possible for you to explicitly widen these string literals using a technique like the one in your answer. Unfortunately, we've defined these macros in a way such that they may expand to multiple string literals. E.g., PRId32 expands to "l" "d".

This is valid, but it does prevent you from widening, because there is no way to prepend an L to the second string literal (to make "d" into L"d"). I'm afraid I don't see a way to make this work without (re)defining the macros yourself.

I've opened a bug internally so that if the compiler does not add support for concatenation of mixed-width literals during preprocessing in the next release, we can revisit these definitions to possibly make it possible to widen them explicitly.

like image 105
James McNellis Avatar answered Oct 15 '22 22:10

James McNellis


I know zip-all about VS C++, but you shouldn't actually need the L prefix for the concatenand of a wide string literal.

 L"%" PRId32 "\n"

should work (and it does with gcc).

From the C11 draft, §6.4.5/5: (as far as I can tell, this was roughly the same in C99, except that C99 didn't have utf-8 literals.)

In translation phase 6, the multibyte character sequences specified by any sequence of adjacent character and identically-prefixed string literal tokens are concatenated into a single multibyte character sequence. If any of the tokens has an encoding prefix, the resulting multibyte character sequence is treated as having the same prefix; otherwise, it is treated as a character string literal. Whether differently-prefixed wide string literal tokens can be concatenated and, if so, the treatment of the resulting multibyte character sequence are implementation-defined.

Also see §7.8.1/7, which provides the example:

uintmax_t i = UINTMAX_MAX; // this type always exists
wprintf(L"The largest integer value is %020"
    PRIxMAX "\n", i);

A similar clause appears in the C++11 standard, §2.14.5/13. (However, in C++03, combining narrow and wide string literals was not allowed.)

In translation phase 6, adjacent string literals are concatenated. If both string literals have the same encoding-prefix, the resulting concatenated string literal has that encoding-prefix. If one string literal has no encoding-prefix, it is treated as a string literal of the same encoding-prefix as the other operand…

Apparently, Visual Studio does not allow this form of literal concatenation.

like image 21
rici Avatar answered Oct 15 '22 20:10

rici