From: Puetz Kevin A Subject: RE: [PATCH v2 1/4] include: Fix undefined char16_t in C11. Message-Id: Date: Wed, 23 Sep 2020 17:43:34 +0000 In-Reply-To: References: <20200917224905.2465-1-PuetzKevinA@JohnDeere.com> > -----Original Message----- > From: Jacek Caban > Sent: Wednesday, September 23, 2020 9:44 AM > > In c++11 char16_t is a distinct fundamental type, > > but in c11 it is merely a typedef in . > > > > Explicitly mention char16_t only in c++11 (where it is built-in), > > otherwise define WCHAR to match u"...", without naming char16_t. > > > > Remove WINE_UNICODE_CHAR16; it is now the default when supported. > > I like the part that uses __cpp_unicode_literals, it would make our > headers much more C++ friendly by default. > > I'm less sure if we want __CHAR16_TYPE__. In practice, it will only > affect C, which is much less strict about types anyway. We assume in > Wine code base that WCHAR is 16-bit unsigned integer. If __CHAR16_TYPE__ > is something else, we shouldn't use it. If it's the same, then there is > little point in using it. I think that the original problem is fixed by > __cpp_unicode_literals change alone, so how about doing just that? __CHAR16_TYPE__ (per C11 standard) is always the same type as uint_least16_t. Which, in turn, is always a typedef for one of the ordinary integer types. So it is just a 16-bit unsigned integer, unless one doesn't exist at all , in which case it's the smallest unsigned integer that can hold 0...65535. It's never a distinct type like char16_t is for c++11/__cpp_unicode_literals. What isn't guaranteed is that the only suitable type is `unsigned short`, it could legally be `unsigned int` (if that was also 16-bit). I don't quite agree that ignoring this is preferable because C "is much less strict about types anyway." 1. The __CHAR16_TYPE__ path applies to C++98 and C++03, which lack __cpp_unicode_literals but might have a C-ish char16_t. So its behavior shouldn't completely ignore c++. 2. C has mostly the same strict-aliasing rules as C++, which would not permit `const unsigned short *` pointing to `unsigned int[]`, even if they are the same size. So when LPCTSTR = TEXT("...") becomes const WCHAR * = u"...", if WCHAR is `short` but __CHAR16_TYPE__ is e.g. `int`, there is a strict-aliasing violation (and undefined behavior) in C too. Now, in practice wine probably doesn't support any platform with 16-bit `int`, So __CHAR16_TYPE__ is just going to be `unsigned short` anyway. This way is pedantically more portable (to various architectures, if they are using gcc or clang which provide __CHAR16_TYPE__) But in practice they will preprocess to the same thing, which makes both the arguments in favor and the arguments against moot. So I'll drop it (after this last attempt to justify it) if that's what you want; I care about char16_t mostly in C++11, but was just trying to fix the C path to be portable too on general principle. Not a hill I need to die on :-)