Как создать строковый литерал UTF-8 в Visual C ++ 2008

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

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 

Также нет «С»:

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

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

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

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

Обновить

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

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

Обновить:

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

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

Оригинал:

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

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

Вот что я нашел:

gcc (v4.3.2 20081105):

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

VC2003:

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

VC2005 +:

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

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

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

В конце концов я решил, что буду избегать стоимости конверсии для всех компиляторов, отличных от 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 

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

Это используется как следующий код. Он легко компилируется и работает правильно в моих тестах на gcc, vc2003 и vc2008:

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

Brofield,

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

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

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

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

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

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

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

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

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

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

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

Независимо, EDITOR может автоматически обнаруживать файлы UTF-8 без спецификации в виде файлов UTF-8.

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

 #pragma execution_character_set("utf-8") 

Он требует Visual Studio 2008 SP1 и следующее исправление:

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

Как насчет этого? Вы сохраняете строки в кодированном файле 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 перед компиляцией, используя этот трюк.

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

 #include  #include  #include  ///////////////////////////////////////////////////////// // 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 vUtf16(1+sNative.length()); // convert std::use_facet< std::ctype >(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 Express на 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(chUtf16); } else if (chUtf16 < 0x7FF) { szUtf8[0] = static_cast(0xC0 | ((chUtf16>>6)&0x1F)); szUtf8[1] = static_cast(0x80 | (chUtf16&0x3F)); } else { szUtf8[0] = static_cast(0xE0 | ((chUtf16>>12)&0xF)); szUtf8[1] = static_cast(0x80 | ((chUtf16>>6)&0x3F)); szUtf8[2] = static_cast(0x80 | (chUtf16&0x3F)); } return reinterpret_cast(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  #include  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; } 

Возможно, попробуйте эксперимент:

 #pragma setlocale(".UTF-8") 

или:

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

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

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

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

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

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

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

введите описание изображения здесь

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

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

Прежде всего, вы должны работать под одной кодовой страницей кодовых страниц, например, с английским, так что 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  #include  #include  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)"); } 

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

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

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

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

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

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

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

Я согласен с Тео Воссе. Прочитайте статью «Абсолютный минимум» Каждый разработчик программного обеспечения абсолютно уверен, должен знать об Unicode и наборах символов (никаких оправданий!) На Joel On Software …

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

  • Что случилось с тысячами предупреждений в стандартных заголовках в MSVC -Wall?
  • Преобразование CString в const char *
  • Как отключить Unicode в проекте VC ++?
  • MSVCR100.dll отсутствует ошибка даже там
  • Ошибка распространения VC ++ 2008: доступ запрещен
  • MSVC не расширяет __VA_ARGS__ правильно
  • Двойное удаление в файле initializer_list vs 2013
  • Почему VS не определяет альтернативные токены для логических операторов?
  • C ++ Метод статического члена вызывает экземпляр classа
  • В Visual Studio C ++, каковы представления распределения памяти?
  • Является !! безопасный способ конвертировать в bool в C ++?
  • Interesting Posts

    Flac2mp3 на mac?

    Несколько графических карт – должны быть одинаковыми?

    Ошибка 80040154 (исключение classа без регистрации) при инициализации VCProjectEngineObject (Microsoft.VisualStudio.VCProjectEngine.dll)

    Вложенная доходность возврата с помощью IEnumerable

    Использование контекста приложения во всем мире?

    Использование акселерометра, гироскопа и компаса для расчета движения устройства в 3D-мире

    Получить имя пользователя Windows с помощью JAVA или JSP

    Не удается скопировать измененные ярлыки на панель задач Windows 7

    как захватить изображение в фоновом режиме без использования приложения камеры

    Значение аббревиатуры SSO в контексте std :: string

    Изменить каталог по умолчанию для Документов и настроек?

    Как определить несколько действий JButton из другого classа

    В чем разница между StreamWriter.Flush () и StreamWriter.Close ()?

    Могу ли я сделать синхронный запрос с волейболом?

    Word 2010 Количество страниц без первой страницы

    Давайте будем гением компьютера.