Есть ли у VC параметр компиляции, такой как "-fexec-charset" в GCC для установки набора символов выполнения?

GCC имеет -finput-charset, -fexec-charset и -fwide-exec-charset три параметра компиляции для указания конкретных кодировок, участвующих в "цепочке компиляции". Как показано ниже:

+--------+   -finput-charset     +----------+    -fexec-charset (or)    +-----+
| source | ------------------->  | compiler |  -----------------------> | exe |
+--------+                       +----------+    -fwide-exec-charset    +-----+

Ссылка: Параметры компилятора GCC

Я нашел вопрос о -finput-charset здесь: Спецификация кодировки исходного кода в MSVС++, например gcc "-finput-charset = CharSet" . Но я хочу знать, имеет ли VC параметр компилятора, например -fexec-charset в GCC, для указать набор символов выполнения.

В Visual Studio я нашел относительный параметр: Project Properties/Configuration Properties/General/Character Set. И значение Use Unicode Character Set. Это делает то же самое, что и -fexec-charset в GCC? Таким образом, я хочу установить набор символов выполнения UTF-8. Как?

Почему я хочу установить кодировку выполнения?

Я пишу приложение на С++, которое должно связываться с сервером db. И кодировка таблиц - utf8. После того, как я построю несколько тестов, тесты будут улавливать исключения, связанные с операциями вставки в таблицах db. Исключения говорят мне, что они соответствуют неправильным строковым значениям. Я полагаю, что это вызвано неправильным правом кодирования? Кстати, есть ли другие способы решения этой проблемы?

Ответ 1

AFAIK, VС++ не имеет флаг командной строки, позволяющий указать набор символов выполнения UTF-8. Однако он (спорадически) поддерживает недокументированные

#pragma execution_character_set("utf-8")`

упоминается здесь.

Чтобы получить эффект флага командной строки с помощью этой прагмы, вы можете написать прагму в заголовке файл, скажем, preinclude.h и предварительно включить этот заголовок в каждую компиляцию, передав флаг /FI preinclude.h. См. эту документацию как установить этот флаг из среды IDE.

Прага была поддержана в VС++ 2010, а затем забыта в VС++ 2012 и снова поддерживается в VС++ 2013

Ответ 2

Следует отметить, что прагма execution_character_set применима только к символьным строковым литералам ("Hello World"), а не к широким символам строки символов (L"Hello World").

Я провел несколько экспериментов, чтобы узнать, как в MSVC реализованы исходные и исполнительные наборы символов. Я провел эксперименты с Visual Studio 2015 в системе Windows, где CP_ACP - 1252 и суммирует результаты следующим образом:

Литералы символов

  • Если MSVC определяет исходный файл как файл Unicode, то есть он кодируется в UTF-8 или UTF-16, он преобразует символы в CP_ACP. Если символ Unicode не находится в диапазоне CP_ACP, MSVC выдает предупреждение C4566 ( "символ, представленный универсальным именем-символом" \U0001D575, не может быть представлен на текущей кодовой странице (1252) "). MSVC предполагает, что набор символов выполнения компилируемого программного обеспечения составляет CP_ACP компилятора. Это означает, что вы должны скомпилировать программное обеспечение под CP_ACP целевой среды, то есть, если вы хотите выполнить программное обеспечение в системе Windows с кодовой страницей 1252, вы должны скомпилировать его по кодовой странице 1252 и не выполнять его в системе с любую другую кодовую страницу. На практике это может сработать, если ваши литералы кодируются ASCII (блок управления C0 и базовый латинский Unicode), поскольку наиболее распространенные кодовые страницы SBCS расширяют эту кодировку. Тем не менее, есть некоторые, которые этого не делают, особенно страницы кода DBCS

  • Если MSVC определяет, что исходный файл не является файлом Unicode, он интерпретирует исходный файл в соответствии с CP_ACP и предполагает, что набор символов выполнения CP_ACP. Как и в файлах Unicode, вы должны скомпилировать программное обеспечение под CP_ACP целевой среды и иметь те же проблемы.

Все функции API "ANSI" Windows API (например, CreateFileA) интерпретируют строки типа LPSTR в соответствии с CP_ACP или CP_THREAD_ACP (по умолчанию это CP_ACP). Нелегко узнать, какие функции используют CP_ACP или CP_THREAD_ACP, поэтому лучше никогда не менять CP_THREAD_ACP.

Широкие буквенные символы

Набор символов выполнения для букв с широким символом всегда является Юникодом, а кодировка - UTF-16LE. Все широкоформатные функции Windows API (например, CreateFile) интерпретируют строку типа LPWSTR как строки UTF-16LE. Это также означает, что wcslen не возвращает число символов Unicode, а число wchar_t символов большой строки символов. В некоторых случаях UTF-16 также отличается от UCS-2.

  • Если MSVC определяет исходный файл как файл Unicode, он преобразует символы в UTF-16LE.
  • Если MSVC определяет, что исходный файл не является файлом Unicode, он считывает файл в соответствии с CP_ACP и расширяет символы до двух байтов без их интерпретации. То есть, если символ закодирован как 0xFF в CP_ACP, он будет записан как 0x00 0xFF независимо от того, является ли символ CP_ACP 0xFF символом Unicode U+00FF.

У меня не было возможности повторить мои эксперименты в системе DBCS Windows, потому что я не говорю на языках, которые обычно используют такие кодовые страницы. Возможно, какое-то тело может повторить эксперименты на такой системе.

Для меня вывод эксперимента заключается в том, что вам следует избегать характера литералы, даже если вы используете прагму execution_character_set.

Прагма просто изменяет, как символьные строковые литералы закодированы в двоичном формате, но не изменяет набор символов выполнения используемых вами библиотек или ядро. Если вы хотите использовать прагму execution_character_set, вам придется перекомпилировать Windows и все другие библиотеки, которые вы используете полностью с прагмой, что, конечно, невозможно. Поэтому я бы рекомендовал не использовать его. Это может работать для некоторых систем, поскольку UTF-8 работает с большинством функций символьных строк в CRT, а CP_ACP обычно включает ASCII, но вы должны проверить, действительно ли эти предположения находятся в вашей целевой среде и действительно ли требуемое усилие этого злоупотребления действительно стоит Это. Более того, прагма, кажется, недокументирована, и я не могу работать в будущих выпусках.

В противном случае вам придется скомпилировать отдельные двоичные файлы для всех кодовых страниц, которые используются в ваших целевых системах. Единственный способ избежать множественных двоичных файлов будет заключаться в том, что вы экртизовываете все строки для ресурсов, кодируемых UTF-16LE, и при необходимости преобразуете строки в CP_ACP. В этом случае вам нужно сохранить сценарии ресурсов (.rc) в качестве UTF-8, вызвать rc с помощью /c65001 (UTF-16LE не работает) и включить строки для всех кодовых страниц, которые используются в ваших целевых систем.

Я бы посоветовал кодировать ваши файлы в кодировке Unicode, например UTF-8 или UTF-16LE, и использовать широкие буквенные символы, если вы не можете экрнализировать строки для ресурсов и скомпилировать с помощью UNICODE и _UNICODE определены. Не рекомендуется использовать струнные и символьные литералы, предпочитая ресурсы. Используйте WideCharacterToMultiByte и MultiByteToWideChar для функций, которые ожидают строки, которые закодированы в соответствии с CP_ACP или какой-либо другой кодовой страницей.

Эвристика обнаружения кодирования источника MSVC лучше всего работает с включенной поддержкой спецификации (даже в UTF-8).

Я не эксперт по азиатским языкам, но я читал, что объединение han в Unicode противоречиво. Поэтому использование Unicode может быть не решением всех проблем, и могут быть случаи, когда он не соответствует требованиям, но я бы сказал, что для языков большинства Unicode лучше всего работает в Windows.

Ошибка Microsoft в том, что она не является явной об этом и документирует поведение своих компиляторов и операционной системы.

Ответ 3

Обновление Visual Studio 2015 2 и более поздних версий поддерживает установку набора символов выполнения:

Вы можете использовать опцию /utf-8, которая объединяет опции /source-charset:utf-8 и /execution-charset:utf-8. По ссылке выше:

В тех случаях, когда файлы с UTF-8 без BOM файлов уже существуют или где происходит смена спецификации, используйте параметр /source -charset: utf-8 для правильного чтения этих файлов.

Использование/execute-charset или /utf -8 может помочь при настройке кода между Linux и Windows, поскольку Linux обычно использует BOM-less файлы UTF-8 и набор символов выполнения UTF-8.

Project Properties/Configuration Properties/General/Character Set устанавливает только макросы Unicode/MBCS, но не набор исходных символов или набор символов выполнения.

Ответ 4

Кредит на @user3998276 Ответ и большой эксперимент.

Заключение говорит мне много.

  • когда встречаются L "string", широкая строка:

    • компилятор сначала обнаруживает кодировку cpp файла, а затем:
      • Unicode → просто используйте utf-16//здесь также может быть преобразование, например u8 в u16.
      • ACP → преобразовать строку Unicode в ACP
  • когда встречается строка "string", обычный строковый литерал:

    • Компилятор
    • сначала обнаруживает кодировку cpp файла, затем
      • Юникод → скрывает символ Юникода символу ACP
      • ACP → просто прочитайте исходный файл в соответствии с ACP

Что касается вашей проблемы, я думаю, что "операции ввода в таблицы db" - это просто вызовите API db inserting. Итак, все, что вам нужно сделать, - это организовать команду, например SQL, в UTF8. Как только API сможет понять вашу команду, он может записать правильное значение (представьте себе двоичный пара) для вас.

Try:

  • В С++ 11 и более поздних версиях вы можете указать строку utf-8 префиксом "u8", например

u8"INSERT INTO table_name (col1, col2,...) VALUES (v1, v2,....)"

http://en.cppreference.com/w/cpp/language/string_literal

  • Используйте стороннюю оболочку строки, например QString из QT.

    Сначала оберните ваш SQL в QString, тогда его можно легко преобразовать в utf8, QByteArray x = mySql.toUtf8(). QByteArray - это просто "массив байтов", поэтому вы можете static_cast его к типу API вставки.

Снова внимательно прочитайте ответ @user3998276, вам может потребоваться изменить кодировку вашего файла cpp на Unicode, если какой-либо символ не может быть представлен в вашей кодовой странице ANSI.