2009-03-27 2 views
56

В VC++ 2003 я мог бы просто сохранить исходный файл как UTF-8, и все строки были использованы как есть. Другими словами, следующий код будет печатать строки, как и на консоли. Если исходный файл был сохранен как UTF-8, то выход будет UTF-8.Как создать строковый литерал UTF-8 в Visual C++ 2008

printf("Chinese (Traditional)"); 
printf("中国語 (繁体)"); 
printf("중국어 (번체)"); 
printf("Chinês (Tradicional)"); 

Я сохранил файл в формате UTF-8 с помощью спецификации UTF-8. Однако при компиляции с VC2008 результаты:

warning C4566: character represented by universal-character-name '\uC911' 
cannot be represented in the current code page (932) 
warning C4566: character represented by universal-character-name '\uAD6D' 
cannot be represented in the current code page (932) 
etc. 

Персонажи, вызывающие эти предупреждения, повреждены. Те, которые соответствуют языку (в данном случае 932 = японский), преобразуются в кодировку локали, т. Е. Shift-JIS.

Я не могу найти способ заставить VC++ 2008 скомпилировать это для меня. Обратите внимание, что не имеет значения, какой язык я использую в исходном файле. Кажется, что не существует языкового стандарта, в котором говорится: «Я знаю, что делаю, поэтому не изменяйте строковые литералы». В частности, бесполезный псевдоязык UTF-8 не работает.

#pragma setlocale(".65001") 
=> error C2175: '.65001' : invalid locale 

Ни делает "C":

#pragma setlocale("C") 
=> see warnings above (in particular locale is still 932) 

Оказывается, что VC2008 силы все символы в указанный (или по умолчанию) локали и локали не может быть UTF-8. Я не хочу менять файл, чтобы использовать escape-строки типа «\ xbf \ x11 ...», потому что тот же источник скомпилирован с использованием gcc, который вполне может иметь дело с файлами UTF-8.

Можно ли указать, что компиляция исходного файла должна оставить строковые литералы нетронутыми?

Чтобы спросить об этом по-другому, какие флажки компиляции можно использовать для указания обратной совместимости с VC2003 при компиляции исходного файла. то есть не изменяйте строковые литералы, используйте их байт для байта, как они есть.

Update

Спасибо за предложения, но я хочу, чтобы избежать WCHAR. Поскольку это приложение имеет дело только с строками в UTF-8, использование wchar потребует от меня преобразовать все строки обратно в UTF-8, что не должно быть ненужным. Вся входная, выходная и внутренняя обработка находится в UTF-8. Это простое приложение, которое отлично работает как в Linux, так и при компиляции с VC2003. Я хочу, чтобы иметь возможность компилировать то же приложение с VC2008 и работать.

Для этого мне понадобится VC2008, чтобы не пытаться преобразовать его в локальную локальную машину (японский, 932). Я хочу, чтобы VC2008 был обратно совместим с VC2003. Я хочу установить языковой стандарт или компилятор, который говорит, что строки используются как есть, по существу, как непрозрачные массивы char, или как UTF-8. Похоже, я мог застрять в VC2003 и gcc, хотя VC2008 пытается быть слишком умным в этом случае.

+1

См. Ответ на новые версии VS: http://stackoverflow.com/questions/19987448/is-there-an-easy-way-to-write-utf-8-octets-in-visual-studio – bames53

+0

Я просто столкнулся с этой проблемой в VS 2012. Он закручивает мою кодировку UTF-8. Почему VS так сломан? Я думаю, что я просто поместил свои данные во внешний файл, где он не будет испорчен. Необходимость работать с багги-компилятором довольно раздражает. BTW, C++ 11 позволяет кодирование указываться как u8 "literal", но VS 2012 не поддерживает это, так что это не поможет. – Joe

ответ

31

Update:

Я решил, что нет гарантированного способа сделать это. Решение, которое я приводил ниже, работает для английской версии VC2003, но не удается при компиляции с японской версией VC2003 (или, возможно, это японская ОС). В любом случае, это не может зависеть от работы. Обратите внимание, что даже объявление всего, поскольку L "" строки не работают (и это болезненно в gcc, как описано ниже).

Вместо этого я считаю, что вам просто нужно укусить пулю и переместить весь текст в файл данных и загрузить его оттуда. Теперь я сохраняю и получаю доступ к тексту в файлах INI через SimpleIni (кросс-платформенная библиотека INI-файлов). По крайней мере, есть гарантия, что он работает, поскольку весь текст выходит из программы.

Оригинал:

Я отвечаю на это сам, так как только Эван появился, чтобы понять эту проблему. Ответы на вопрос о том, что такое Unicode и как использовать wchar_t, не имеют отношения к этой проблеме, поскольку речь идет не о интернационализации, а также о непонимании Unicode, кодировании символов. Я ценю вашу попытку помочь, хотя, извини, если я не был достаточно ясен.

Проблема в том, что у меня есть исходные файлы, которые необходимо перекрестно скомпилировать под различными платформами и компиляторами. Программа обрабатывает UTF-8. Он не заботится о каких-либо других кодировках. Я хочу иметь строковые литералы в UTF-8, как в настоящее время работает с gcc и vc2003. Как мне это сделать с VC2008? (то есть обратное совместимое решение).

Это то, что я нашел:

НКУ (v4.3.2 20081105):

  • строковые литералы используются как есть (необработанные строки)
  • поддерживает UTF-8 закодированные исходные файлы
  • исходные файлы не должны иметь UTF-8 BOM

VC2003 :

  • строковые литералы используются как есть (необработанные строки)
  • поддерживает UTF-8 закодированные исходные файлы
  • исходные файлы могут или не могут быть UTF-8 BOM (не имеет значения)

VC2005 +:

  • строковые литералы массируют компилятором (без сырья строк)
  • символ строковых литералов повторно кодируется для заданной локали
  • UTF-8 не поддерживается в качестве целевой местности
  • исходные файлы должны иметь UTF-8 BOM

Итак, простой ответ заключается в том, что для этой конкретной цели VC2005 + сломан и не обеспечивает обратный совместимый путь компиляции. Единственный способ получить строки Unicode в скомпилированную программу - через UTF-8 + BOM + wchar, что означает, что мне нужно преобразовать все строки обратно в UTF-8 во время использования.

Нет простого кросс-платформенного метода преобразования wchar в UTF-8, например, какой размер и кодировка является wchar? В Windows UTF-16. На других платформах? Различается. Для получения дополнительной информации см. ICU project.

В конце концов я решил, что буду избегать стоимости конверсии для всех компиляторов, отличных от vc2005 +, с источником, как показано ниже.

#if defined(_MSC_VER) && _MSC_VER > 1310 
// Visual C++ 2005 and later require the source files in UTF-8, and all strings 
// to be encoded as wchar_t otherwise the strings will be converted into the 
// local multibyte encoding and cause errors. To use a wchar_t as UTF-8, these 
// strings then need to be convert back to UTF-8. This function is just a rough 
// example of how to do this. 
# define utf8(str) ConvertToUTF8(L##str) 
const char * ConvertToUTF8(const wchar_t * pStr) { 
    static char szBuf[1024]; 
    WideCharToMultiByte(CP_UTF8, 0, pStr, -1, szBuf, sizeof(szBuf), NULL, NULL); 
    return szBuf; 
} 
#else 
// Visual C++ 2003 and gcc will use the string literals as is, so the files 
// should be saved as UTF-8. gcc requires the files to not have a UTF-8 BOM. 
# define utf8(str) str 
#endif 

Обратите внимание, что этот код является просто упрощенным примером. Производственное использование должно было бы очистить его различными способами (безопасность потока, проверка ошибок, проверка размера буфера и т. Д.).

Используется как следующий код. Она компилируется и работает правильно в моих тестах на НКУ, VC2003, VC2008 и:

std::string mText; 
mText = utf8("Chinese (Traditional)"); 
mText = utf8("中国語 (繁体)"); 
mText = utf8("중국어 (번체)"); 
mText = utf8("Chinês (Tradicional)"); 
+0

Отличный ответ и решение, спасибо. – TinyRacoon

+1

** Время исполнения **, вы издеваетесь надо мной? Просто прокрутите ** [ниже] (http://stackoverflow.com/a/2411769/485343) ** для гораздо более простого решения времени компиляции (просто сохраните исходный код в UTF-8). – rustyx

0

У меня была аналогичная проблема, решение было сохранить в UTF8 withou стрелы, используя расширенные возможности сохранения

+3

К сожалению, это не работает для меня. Я получаю ошибки компиляции, поскольку компилятор тогда предполагает, что исходный файл находится в Shift-JIS и поэтому интерпретирует строки по-разному. – brofield

+0

@brofield Я обнаружил, что системная локаль заставит компилятор сделать такое предположение. Попробуйте изменить языковой стандарт вашей системы на английский. – raymai97

-5

Прочитайте статьи. Во-первых, вы не хотите UTF-8. UTF-8 - это всего лишь способ представления символов. Вам нужны широкие символы (wchar_t). Вы записываете их как L "yourtextgoeshere". Тип этого литерала - wchar_t *. Если вы спешите, просто найдите wprintf.

+2

Я не хочу конвертировать в wchar, потому что мне просто нужно снова преобразовать все строки обратно в UTF-8. Я хочу, чтобы VC2008 оставил мои строковые литералы без изменений. – brofield

+0

OP нуждается в UTF-8. Я не уверен, как преобразование в wchar решает его проблему. –

15

Хотя, вероятно, лучше использовать широкие строки, а затем конвертировать по мере необходимости в UTF-8. Я думаю, что ваш лучший выбор - это, как вы уже упоминали, использовать шестнадцатеричные escape-последовательности в строках. Например, вы хотели код \uC911, вы могли бы просто сделать это.

const char *str = "\xEC\xA4\x91"; 

Я считаю, что это будет работать нормально, просто не очень удобным для чтения, так что если вы сделаете это, пожалуйста прокомментируйте его объяснить.

+2

+1, но я бы предпочел трехзначные восьмеричные escape-последовательности над шестнадцатеричными экранами, из-за максимального ограничения шестнадцатеричного перехода. Пример «Ond bråd död i Venedig» в октете: '' Ond bra \ 314 \ 212d do \ 314 \ 210d i Venedig "', в hex: '" Ond bra \ xCC \ x8A "" d do \ xCC \ x88 "" ди Венедиг ". – dalle

+0

Это не представление \ uC911 в UTF-8. – Lev

+0

@ Lev: достаточно справедливо, исправление. –

14

Brofield,

У меня была точно такая же проблема и как раз наткнулся на решение, которое не требует преобразования вашего источника строки в широкие символы и обратно: сохраните исходный файл как UTF-8 без подпись и VC2008 оставят его в покое. Отлично работал, когда я решил отказаться от подписи. Подводя итог:

Unicode (UTF-8 без подписи) - Codepage 65001, не выдает предупреждение c4566 в VC2008 и не вызывает ошибки в VC, в то время как Codepage 65001 (UTF-8 с подписями)) делает бросок c4566 (как вы нашли).

Надеюсь, что это не слишком поздно, чтобы помочь вам, но это может ускорить ваше приложение VC2008, чтобы удалить обходной путь.

+0

Хорошо, это работает для меня. – ybungalobill

+1

-1, Не работал для меня (английский VS2010). Я получаю предупреждение C4819 и многие другие синтаксические ошибки. Однако я работаю в Корее, и у меня есть настройки ОС для отображения строк юникода на корейском языке. – Verax

+0

Что-то вроде std :: string jp1 = "て す と"; работает с VS2012, если файл сохранен "Unicode (UTF-8 без подписи) - Codepage 65001" – Echsecutor

4

Как насчет этого? Вы сохраняете строки в кодированном файле UTF-8, а затем предварительно обрабатываете их в ASCII-кодированном исходном файле C++. Вы сохраняете кодировку UTF-8 внутри строки, используя шестнадцатеричные escape-последовательности. Строка

"中国語 (繁体)" 

преобразуется в

"\xE4\xB8\xAD\xE5\x9B\xBD\xE8\xAA\x9E (\xE7\xB9\x81\xE4\xBD\x93)" 

Конечно, это неразборчивое любым человеком, и цель состоит в том только, чтобы избежать проблем с компилятором.

Вы можете использовать препроцессор C++ для ссылки на строки в преобразованном заголовочном файле или вы можете преобразовать весь источник UTF-8 в ASCII перед компиляцией, используя этот трюк.

1

Может быть, попробовать эксперимент:

#pragma setlocale(".UTF-8") 

или:

#pragma setlocale("english_england.UTF-8") 
1

У меня была аналогичная проблема. Строковые литералы UTF-8 были преобразованы в текущую системную кодовую страницу во время компиляции - я только что открыл файлы .obj в hex-viewer, и они уже были искалечены. Например, символ ć был всего один байт.

Решение для меня состояло в том, чтобы сохранить в UTF-8 и БЕЗ спецификации. Вот как я обманул компилятор. Теперь он считает, что это обычный источник, и он не переводит строки. В файлах .obj ć теперь два байта.

Не обращайте внимания на некоторых комментаторов. Я понимаю, что вы хотите - я тоже хочу: источник UTF-8, созданные UTF-8 файлы, входные файлы UTF-8, UTF-8 по линиям связи без перевода.

Может быть, это помогает ...

+0

Хорошо, что он работает на вас. Я считаю, что есть проблемы в этом маршруте, если вы используете языковой стандарт, не являющийся английским. У меня есть японский компилятор и японский системный язык, и это не сработало для меня, поскольку казалось, что он пытался преобразовать строковые литералы из Shift-JIS, которые потерпели неудачу, потому что они были UTF-8. – brofield

13

File/Save Advanced Options/Encoding: "Unicode (UTF-8 без подписи) - Codepage 65001"

+3

Попробуйте выполнить компиляцию с японской версией компилятора. – brofield

+3

Вы говорите, что это не работает «без подписи». Это, безусловно, очень странно, поскольку компилятор не распознает вход как вход UTF-8 без дополнительной обработки. Вы говорите, что японская версия выполняет такую ​​логику; очень интересно. Однако трюк работает для русского. – Vladius

+1

Трюк, очевидно, должен работать на любом кодировании, которое оставляет часть ASCII неповрежденной. То есть UTF-8, ISO-8859-x, KOI8-R и другие. – jmster

3

Портативное преобразование из любой родной кодировки у вас есть с помощью char_traits :: widen().

#include <locale> 
#include <string> 
#include <vector> 

///////////////////////////////////////////////////////// 
// NativeToUtf16 - Convert a string from the native 
//     encoding to Unicode UTF-16 
// Parameters: 
// sNative (in): Input String 
// Returns:  Converted string 
///////////////////////////////////////////////////////// 
std::wstring NativeToUtf16(const std::string &sNative) 
{ 
    std::locale locNative; 

    // The UTF-16 will never be longer than the input string 
    std::vector<wchar_t> vUtf16(1+sNative.length()); 

    // convert 
    std::use_facet< std::ctype<wchar_t> >(locNative).widen(
     sNative.c_str(), 
     sNative.c_str()+sNative.length(), 
     &vUtf16[0]); 

    return std::wstring(vUtf16.begin(), vUtf16.end()); 
} 

В теории, обратный путь из UTF-16 в UTF-8 должно быть так же легко, но я обнаружил, что UTF-8 локали, не работают должным образом на моей системе (VC10 Экспресс на Win7).

Таким образом, я написал простой конвертер на основе RFC 3629.

///////////////////////////////////////////////////////// 
// Utf16ToUtf8 - Convert a character from UTF-16 
//     encoding to UTF-8. 
//     NB: Does not handle Surrogate pairs. 
//      Does not test for badly formed 
//      UTF-16 
// Parameters: 
// chUtf16 (in): Input char 
// Returns:  UTF-8 version as a string 
///////////////////////////////////////////////////////// 
std::string Utf16ToUtf8(wchar_t chUtf16) 
{ 
    // From RFC 3629 
    // 0000 0000-0000 007F 0xxxxxxx 
    // 0000 0080-0000 07FF 110xxxxx 10xxxxxx 
    // 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 

    // max output length is 3 bytes (plus one for Nul) 
    unsigned char szUtf8[4] = ""; 

    if (chUtf16 < 0x80) 
    { 
     szUtf8[0] = static_cast<unsigned char>(chUtf16); 
    } 
    else if (chUtf16 < 0x7FF) 
    { 
     szUtf8[0] = static_cast<unsigned char>(0xC0 | ((chUtf16>>6)&0x1F)); 
     szUtf8[1] = static_cast<unsigned char>(0x80 | (chUtf16&0x3F)); 
    } 
    else 
    { 
     szUtf8[0] = static_cast<unsigned char>(0xE0 | ((chUtf16>>12)&0xF)); 
     szUtf8[1] = static_cast<unsigned char>(0x80 | ((chUtf16>>6)&0x3F)); 
     szUtf8[2] = static_cast<unsigned char>(0x80 | (chUtf16&0x3F)); 
    } 

    return reinterpret_cast<char *>(szUtf8); 
} 


///////////////////////////////////////////////////////// 
// Utf16ToUtf8 - Convert a string from UTF-16 encoding 
//     to UTF-8 
// Parameters: 
// sNative (in): Input String 
// Returns:  Converted string 
///////////////////////////////////////////////////////// 
std::string Utf16ToUtf8(const std::wstring &sUtf16) 
{ 
    std::string sUtf8; 
    std::wstring::const_iterator itr; 

    for (itr=sUtf16.begin(); itr!=sUtf16.end(); ++itr) 
     sUtf8 += Utf16ToUtf8(*itr); 
    return sUtf8; 
} 

Я считаю, что это должно работать на любой платформе, но я не был в состоянии проверить это, кроме как на моей системе, так что это может иметь ошибок.

#include <iostream> 
#include <fstream> 

int main() 
{ 
    const char szTest[] = "Das tausendschöne Jungfräulein,\n" 
          "Das tausendschöne Herzelein,\n" 
          "Wollte Gott, wollte Gott,\n" 
          "ich wär' heute bei ihr!\n"; 

    std::wstring sUtf16 = NativeToUtf16(szTest); 
    std::string sUtf8 = Utf16ToUtf8(sUtf16); 

    std::ofstream ofs("test.txt"); 
    if (ofs) 
     ofs << sUtf8; 
    return 0; 
} 
+0

Вы пропустили всю точку вопроса. Требовалось не оставлять UTF-8 от компиляции до обработки. Кроме того, Windows не поддерживает UTF-8 как кодовую страницу (из-за предположения, что все MBCS не более 2 байтов). См. Http://blogs.msdn.com/b/michkap/archive/2007/01/03/1392379.aspx – brofield

+0

Это не UTF-16, это UCS-2. – dalle

0

Итак, все, что нужно изменить. Теперь у меня есть решение.

Прежде всего, вы должны работать под одной кодовой страницей одного байта, например, на английском языке, так что cl.exe не получит коды, чтобы стать хаосом.

Во-вторых, сохраните исходный код в спецификации UTF8-NO, обратите внимание, NO-BOM, а затем скомпилируйте с помощью cl.exe, не называя каких-либо C API, таких как printf wprint, все эти сотрудники не работая, я не знаю, почему:) .... может иметь исследование позже ...

Тогда просто компилируй и запустите, вы увидите результат ..... моя электронная почта luoyonggang, (Google) надежда на некоторые ......

WScript:

#! /usr/bin/env python 
# encoding: utf-8 
# Yonggang Luo 

# the following two variables are used by the target "waf dist" 
VERSION='0.0.1' 
APPNAME='cc_test' 

top = '.' 

import waflib.Configure 

def options(opt): 
    opt.load('compiler_c') 

def configure(conf): 
    conf.load('compiler_c') 
    conf.check_lib_msvc('gdi32') 
    conf.check_libs_msvc('kernel32 user32') 

def build(bld): 
    bld.program(
     features = 'c', 
     source = 'chinese-utf8-no-bom.c', 
     includes = '. ..', 
     cflags = ['/wd4819'], 
     target = 'myprogram', 
     use  = 'KERNEL32 USER32 GDI32') 

Запуск сценария run.bat

rd /s /q build 
waf configure build --msvc_version "msvc 6.0" 
build\myprogram 

rd /s /q build 
waf configure build --msvc_version "msvc 9.0" 
build\myprogram 

rd /s /q build 
waf configure build --msvc_version "msvc 10.0" 
build\myprogram 

Исходный код main.c:

//encoding : utf8 no-bom 
#include <stdio.h> 
#include <string.h> 

#include <Windows.h> 

char* ConvertFromUtf16ToUtf8(const wchar_t *wstr) 
{ 
    int requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, 0, 0, 0, 0); 
    if(requiredSize > 0) 
    { 
     char *buffer = malloc(requiredSize + 1); 
     buffer[requiredSize] = 0; 
     WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, requiredSize, 0, 0); 
     return buffer; 
    } 
    return NULL; 
} 

wchar_t* ConvertFromUtf8ToUtf16(const char *cstr) 
{ 
    int requiredSize = MultiByteToWideChar(CP_UTF8, 0, cstr, -1, 0, 0); 
    if(requiredSize > 0) 
    { 
     wchar_t *buffer = malloc((requiredSize + 1) * sizeof(wchar_t)); 
     printf("converted size is %d 0x%x\n", requiredSize, buffer); 
     buffer[requiredSize] = 0; 
     MultiByteToWideChar(CP_UTF8, 0, cstr, -1, buffer, requiredSize); 
     printf("Finished\n"); 
     return buffer; 
    } 
    printf("Convert failed\n"); 
    return NULL; 
} 

void ShowUtf8LiteralString(char const *name, char const *str) 
{ 
    int i = 0; 
    wchar_t *name_w = ConvertFromUtf8ToUtf16(name); 
    wchar_t *str_w = ConvertFromUtf8ToUtf16(str); 

    printf("UTF8 sequence\n"); 
    for (i = 0; i < strlen(str); ++i) 
    { 
     printf("%02x ", (unsigned char)str[i]); 
    } 

    printf("\nUTF16 sequence\n"); 
    for (i = 0; i < wcslen(str_w); ++i) 
    { 
     printf("%04x ", str_w[i]); 
    } 

    //Why not using printf or wprintf? Just because they do not working:) 
    MessageBoxW(NULL, str_w, name_w, MB_OK); 
    free(name_w); 
    free(str_w); 

} 

int main() 
{ 
    ShowUtf8LiteralString("English english_c", "Chinese (Traditional)"); 
    ShowUtf8LiteralString("简体 s_chinese_c", "你好世界"); 
    ShowUtf8LiteralString("繁体 t_chinese_c", "中国語 (繁体)"); 
    ShowUtf8LiteralString("Korea korea_c", "중국어 (번체)"); 
    ShowUtf8LiteralString("What? what_c", "Chinês (Tradicional)"); 
} 
+0

К сожалению, я был после кросс-платформенного решения, которое работает на неанглийских локалях в Windows, поэтому ваше решение не удается для моего использования в обоих направлениях. Та задумался об этом. – brofield

+0

Да, это абсолютно не так :), только из-за non_English всегда будет MBCS с 2 байтами, например, на китайском, я работал над подключением cl.exe, введя его. Чтобы его можно было настроить, прочитав некоторую переменную среды :) – lygstate

5

Из комментария к этому очень хороший блог
«Использование UTF-8 в качестве внутреннего представления для строк в C и C++ с Visual Studio»
=>http://www.nubaria.com/en/blog/?p=289

#pragma execution_character_set("utf-8") 

It requires Visual Studio 2008 SP1, and the following hotfix:

http://support.microsoft.com/kb/980263 ....

+1

+1, хотя это, по-видимому, в настоящее время не поддерживается в VS2012: http://connect.microsoft.com/VisualStudio/feedback/details/773186/pragma-execution- character-set-utf-8-didnt-support-in-vc-2012 –

8

Visual C++ (2005+) COMPILER стандартное поведение для исходных файлов:

  • кодировка CP1252 (для этого примера, западноевропейская кодовая страница):
    • "Ä"C4 00
    • 'Ä'C4
    • L"Ä"00C4 0000
    • L'Ä'00C4
  • UTF-8 без BOM:
    • "Ä"C3 84 00 (= UTF-8)
    • 'Ä' → предупреждение: мульти-характер постоянной
    • "Ω"E2 84 A6 00 (= UTF-8, как и следовало ожидать)
    • L"A"00C3 0084 0000 (неправильно!)
    • L'Ä' → предупреждение: мульти-символьной константы
    • L"Ω"00E2 0084 00A6 0000 (неправильно!)
  • UTF-8 с BOM:
    • "Ä"C4 00 (= кодировка CP1252, не более UTF-8),
    • 'Ä'C4
    • "Ω" → ошибка: невозможно преобразовать в CP1252!
    • L"Ä"00C4 0000 (правильный)
    • L'Ä'00C4
    • L"Ω"2126 0000 (правильный)

Вы видите, C компилятор обрабатывает UTF-8 файлы без BOM таким же образом, как кодировка CP1252. В результате компилятор не может смешивать строки UTF-8 и UTF-16 в скомпилированный вывод! Таким образом, вы должны решить для одного файла исходного кода:

  • либо использование UTF-8 с BOM и генерировать только UTF-16 строк (т.е. всегда используйте L префикс),
  • или UTF-8 без спецификации и генерировать только строки UTF-8 (т. е. никогда не использовать префикс L).
  • 7-битный ASCII символы не участвуют и могут быть использованы с или без L префикса

Самостоятельно, редактор может автоматически обнаружить UTF-8 без BOM файлов в UTF-8 файлов.

0

UTF-8 исходные файлы

  • Без BOM: рассматриваются как сырье, за исключением, если ваша система использует> 1 байт/символ кодовая (например, Shift, JIS). Вам нужно сменить системную кодовую страницу на один байт, а затем вы сможете использовать символы Unicode внутри литералов и скомпилировать без проблем (по крайней мере, я надеюсь).
  • С BOM: есть ли символы и строковые литералы, преобразованные в кодовую страницу системы во время компиляции. Вы можете проверить текущую кодовую страницу системы с помощью GetACP(). AFAIK, нет способа установить системную кодовую страницу до 65001 (UTF-8), поэтому, следовательно, нет возможности использовать UTF-8 напрямую с спецификацией.

Единственный переносимый и независимый от компилятора способ - использовать кодировку ASCII и escape-последовательности, поскольку нет никаких гарантий того, что какой-либо компилятор примет кодированный файл UTF-8.

+0

Собственно, компилятор llvm действительно принимает кодированные файлы UTF-8. Он также может быть исправлен, чтобы разрешать имена переменных UTF-8 (имена переменных на выбранном вами языке!). Что касается «портативных», это было проблемой, так как я писал программное обеспечение. –

1

Я знаю, что опаздываю на вечеринку, но мне кажется, что мне нужно spread this out. Для Visual C++ 2005 и выше, если исходный файл не содержит спецификации (байтовый порядок), а языковой стандарт вашей системы не является английским, VC будет считать, что ваш исходный файл не находится в Юникоде.

Чтобы получить ваши UTF-8 исходные файлы компилируются правильно, вы должны сохранить в UTF-8 без BOM кодирования и языка системы (не Unicode язык) должен быть английский.

enter image description here

+0

Не знаете, почему, но кажется, что ссылка сломана, так вот вот новая: https://raymai97.github.io/myblog/msvc-support-utf8-string-literal-since-vc6 – raymai97

0

У меня была аналогичная проблема компиляции UTF-8 узкие (полукокса) строковых литералов и то, что я обнаружил, в основном я должен был иметь как BOM UTF-8 и #pragma execution_character_set("utf-8") [1], или ни BOM ни прагма [2]. Использование одного без другого привело к некорректному преобразованию.

Я задокументированы детали на https://github.com/jay/compiler_string_test

[1]: Visual Studio 2012 не поддерживает execution_character_set. Visual Studio 2010 и 2015 он отлично работает, и, как вы знаете, с патчем в 2008 году он отлично работает.

[2]: Некоторые комментарии в этой теме отметили, что использование ни спецификации, ни прагмы не может привести к некорректному преобразованию для разработчиков, использующих локальную кодовую страницу, которая является многобайтовой (например, Япония).

Смежные вопросы