У 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
- это символ UnicodeU+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
- компилятор сначала обнаруживает cpp-file-encoding, затем:
-
когда встретимся "string", обычный строковый литерал:
- компилятор сначала обнаруживает cpp-file-encoding, затем
- Unicode --> скрыть символ Юникода в символ ACP
- ACP --> просто прочитайте исходный файл в соответствии с ACP
- компилятор сначала обнаруживает cpp-file-encoding, затем
Что касается вашей проблемы, я думаю, что "операции вставки в таблицы БД" - это просто вызовите вставка 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 не может быть представлен какой-либо символ.