Есть ли у 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.