5

I want to pass a QString variable to a function with const wchar_t* argument.

Safe solution is:

void foo(const wchar_t*);
QString x = "test";
foo(x.toStdWString().c_str());

but it has overhead of converting to wstring. Is there any faster solution?

How about this solution? Is it safe and portable?

foo(reinterpret_cast<const wchar_t*>(x.constData()));
A.Danesh
  • 844
  • 11
  • 40

2 Answers2

6

No, the reinterpret cast is not safe and will not work on some platforms where the encoding is different. QChar is 16-bit and the internal encoding is UTF-16, but on Linux wchar_t is 32-bit UCS-4 encoding.

The cast would happen to work (it's still undefined behaviour, but msc++ does not currently do anything that would break it) on Windows where wchar_t is forever stuck at 16 bit, but the point of using Qt is being portable, right?

Note, that the conversion via std::wstring is as efficient as you can get. Given the difference in encoding memory has to be allocated once, which is managed by the std::wstring (the return copy can be elided even in C++98) and std::wstring::c_str() is a trivial getter.

Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
  • The cast is **always** wrong. Either `wchar_t` is identical to `unsigned short`, and no cast is needed, or else they are separate types, and the cast invokes illegal aliasing (strict aliasing violation aka type punning). – Ben Voigt Apr 17 '14 at 05:35
  • @BenVoigt: Yes. But msc++ does not optimize based on strict aliasing and I even recall Microsoft saying somewhere they don't plan it, because they are aware how much code that violates it exists in the wild (and probably have good chunk of it themselves). I reworded the paragraph a bit. – Jan Hudec Apr 17 '14 at 06:52
  • The most efficient way is `toWCharArray` which can avoid dynamic memory allocation and does not need to construct (and destruct) an `std::wstring` instance. – user362515 May 06 '16 at 14:27
-1

If x.constData gives you data addressable as const wchar_t*, you won't need a cast.

Any situation which won't compile without a cast, is badly broken (illegal aliasing and most likely also incompatible encoding).

It looks like the correct way is x.utf16() (no cast), and even then only when wchar_t is unsigned short. See http://qt-project.org/doc/qt-4.8/qstring.html#utf16

QString is always UTF-16, so if wchar_t isn't, then there is no method without conversion.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • No! it gives QChar*. and QChar typedefed to unsigned short. – A.Danesh Apr 17 '14 at 04:48
  • @A.Danesh: `QChar` looks like a class, not a `typedef`. Anyway, see http://stackoverflow.com/a/7360480/103167 – Ben Voigt Apr 17 '14 at 04:50
  • 1
    -1 after the edit. The whole point is that `QString` is UTF-16, but `wchat_t` is **NOT!** The intention of the specification is clearly that `wchar_t` is constant-width encoding, which for Unicode 3 and newer takes 4 bytes (3, but 3-byte types are inpractical) and some systems follow that. The fact that Windows API is now stuck with 16-bit `wchar_t` due to baking it into system calls notwithstanding. – Jan Hudec Apr 17 '14 at 04:56
  • 2
    Also, `QString::utf16()` **does** need a cast to `const wchar_t *`, because `wchar_t` is a distinct type not equal to `unsigned short` (required by C++ specification) unless you are compiling with MSVC++ and set the bug-compatibility option `/Zc:wchar_t-`. – Jan Hudec Apr 17 '14 at 05:26
  • @Jan: Your comments seem to agree with my answer. Edited a bit for clarity. But the `QString` content can be used directly only on systems where `wchar_t` is `unsigned short`. Otherwise you need a conversion. Not a cast. – Ben Voigt Apr 17 '14 at 05:34
  • 1
    @BenVoigt: And there are _no_ systems where `wchar_t` is `unsigned short`, because C++ standard requires that it isn't. MSVC++ has a backward compatibility option, `/Zc:wchar_t-`, that makes `wchar_t` a typedef for `unsigned char`, but it only exists to simplify compiling ancient code, is not selected by default and is not compatible with most libraries you'll get. – Jan Hudec Apr 17 '14 at 06:44
  • Note, that C differs. In C, `wchar_t` can be alias for some integral type. But in C++ it is a distinct primitive type. But Qt is C++, so what C does is not relevant. `g++` and `clang++` always treat `wchar_t` as distinct type and I have not seen non-windows platform using any other compiler for quite long. – Jan Hudec Apr 17 '14 at 06:45