1

我的尝试看起来很老套,而且过于复杂。有没有一种简单的方法可以在 Windows 和 macOS 上将 ASCII 转换为 UTF16?

(请注意,prUTF16Char我无法更改)

尝试(通过https://stackoverflow.com/a/54376330编写)

序幕

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#if defined(__APPLE__) && defined(__MACH__)
#include <xcselect.h>
#include <wchar.h>
#include <CoreFoundation/CoreFoundation.h>
typedef unsigned short int prUTF16Char;
#else
typedef wchar_t prUTF16Char;
#endif

#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define PROJECT_NAME "foo"

功能

void copy2ConvertStringLiteralIntoUTF16(const wchar_t* inputString, prUTF16Char* destination) {
    size_t length = wcslen(inputString);
#if (defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)) && defined(PLUGIN_MODE)
    wcscpy_s(destination, length + 1, inputString);
#elif defined(__APPLE__) && defined(__MACH__)
    CFRange range = {0, 150}; range.length = length;
    CFStringRef inputStringCFSR = CFStringCreateWithBytes(
        kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(inputString),
        length * sizeof(wchar_t), kCFStringEncodingUTF32LE, false);
    CFStringGetBytes( inputStringCFSR, range, kCFStringEncodingUTF16, 0, false,
                      reiterpret_cast<UInt8 *>(destination), length * (sizeof (prUTF16Char)), NULL);
    destination[length] = 0; // Set NULL-terminator
    CFRelease(inputStringCFSR);
#endif
}

const prUTF16Char * to_wchar(const char* message) {
    const size_t cSize = strlen(message);
    wchar_t *w_str = new wchar_t[cSize];
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
    size_t outSize;
    mbstowcs_s(&outSize, w_str, cSize, message, cSize-1);
    return w_str;
#else
    mbstowcs(w_str, message, cSize);
#endif
#if defined(__APPLE__) && defined(__MACH__)
    prUTF16Char *ut16str = new prUTF16Char[cSize];
    copy2ConvertStringLiteralIntoUTF16(w_str, ut16str);
    return ut16str;
#else
    return w_str;
#endif
}

然后我可以定义一个全局变量:

static const prUTF16Char* PROJECT_NAME_W =
#if defined(__APPLE__) && defined(__MACH__)
    to_wchar
#elif defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
    WIDEN
#endif
        (PROJECT_NAME);

通用打印函数的主体采用message

#if WCHAR_UTF16
wprintf(L"%s",
#else
    printf("%ls\n",
#endif
    message);

全面尝试:

https://github.com/SamuelMarks/premiere-pro-cmake-plugin/blob/f0d2278/src/common/logger.cpp [从C++重写为C]

错误:

错误:初始化元素不是编译时常量


编辑:超级hacky,但使用@barmak-shemirani 的解决方案我可以:

#if defined(__APPLE__) && defined(__MACH__)
extern
#elif defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
static
#endif
const prUTF16Char* PROJECT_NAME_W
#if defined(__APPLE__) && defined(__MACH__)
    ;
#elif defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
    WIDEN(PROJECT_NAME);
#endif

…并且仅freeextern变体上初始化和。

4

1 回答 1

1

message包括空终止字符。strlen不计算最后一个字符,cSize必须增加1.

如果例如在非英语计算机上键入,通常您需要调用setlocal 。但是如果保证是ASCIImessage也没关系。message

窗口示例:

const wchar_t* to_wchar(const char* message) 
{ 
    const size_t cSize = strlen(message) + 1;
    //wchar_t* w_str = new wchar_t[cSize]; using C++?
    wchar_t* w_str = malloc(cSize * sizeof(wchar_t));

    size_t outSize;
    mbstowcs(w_str, message, cSize);
    // or mbstowcs_s(&outSize, w_str, cSize, message, cSize);

    return w_str;
}

请注意,wchar_t在 Windows 中是 2 个字节,在 POSIX 中是 4 个字节。那么 UTF-16 有 2 个不同的版本,little-endian 和 big-endian。UTF-16 对于 ASCII 等效代码每个字符有 2 个字节,但对于某些非拉丁语言有 4 个字节。

您应该考虑 UTF-8 输出。大多数 Windows 程序都准备好从文件或网络中读取 UTF-8。

Windows 字节输出"123"

49 00 50 00 51 00 00 00 <- little-endian
0  49 00 50 00 51 00 00 <- big-endian

上述代码的 Linux 字节输出(Winodws 不会将其识别为 UTF-16):

49 00 00 00 50 00 00 00 51 00 00 00 00 00 00 00 

如果您 100% 确定消息是 ASCII,则可以编写自己的函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef unsigned short prUTF16Char;//remove this line later

prUTF16Char* to_wchar(const char* message)
{
    if (!message) return NULL;

    size_t len = strlen(message);
    int bufsize = (len + 1) * 2;
    char* buf = malloc(bufsize);

    int little_endian = 1;
    little_endian = ((char*)&little_endian)[0];
    memset(buf, 0, bufsize);
    for (size_t i = 0; i < len; i++)
        buf[i * 2 + little_endian ? 0 : 1] = message[i];

    return (prUTF16Char*)buf;
}

prUTF16Char* wstr;
int main()
{
    wstr = to_wchar("ASCII");
    wprintf(L"%s\n", wstr);
    free(wstr);
    return 0;
}
于 2021-09-25T08:20:04.240 回答