У 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 здесь: спецификация кодировки исходных кодировок в MSVC++, например gcc "- finput-charset=CharSet". Но я хочу знать, так ли это!--5--> имеет параметр компилятора, например -fexec-charset в GCC к укажите набор символов выполнения.

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

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

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

4 ответов


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

#pragma execution_character_set("utf-8")

называют здесь.

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

pragma была поддержана в VC++ 2010, затем забыта в VC++ 2012 и поддерживается снова в VC++


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

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

персонаж литералы

  • если MSVC определяет исходный файл как файл Unicode, то есть он закодирован в UTF-8 или UTF-16, он преобразует символы в CP_ACP. Если символ Юникода не находится в диапазоне 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 Windows" ANSI " (например,CreateFileA) интерпретируйте строки типа LPSTR по данным CP_ACP или CP_THREAD_ACP (по умолчанию CP_ACP). Нелегко выяснить, какие функции используют CP_ACP или CP_THREAD_ACP так что лучше никогда не менять CP_THREAD_ACP.

широкие литералы символов

набор символов выполнения для широких символьных литералов всегда является Unicode, а кодировка-UTF-16LE. Все широкие функции Windows API символов (например,CreateFile) интерпретировать строку типа LPWSTR как строки UTF-16LE. Это также подразумевает, что wcslen не возвращает количество символов Юникода, но число 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 ПРАГМА.

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

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

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

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

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

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


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

вы можете использовать опцию /utf-8 который сочетает в себе опции /source-charset:utf-8 и /execution-charset:utf-8. По ссылке выше:

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

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

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


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

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

  • при встрече L "строка", широкая строка:

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

    • компилятор сначала обнаруживает cpp-file-encoding, затем
      • Unicode --> скрыть символ Юникода в символ ACP
      • ACP --> просто прочитайте исходный файл в соответствии с ACP

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

попробуй:

  • в c++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 не может быть представлен какой-либо символ.