Как правильно использовать параметр компилятора s-finput-charset g++для компиляции исходного файла, отличного от UTF-8?

Я пытаюсь скомпилировать исходный файл UTF-16BE C++ в G++ с параметром компилятора-finput-charset, но я всегда получаю кучу ошибок. Более детально следовать.

моя среда (в CentOS Linux):

  • g++: 4.1.2
  • iconv: 2.5
  • язык Linux (в терминале): LANG="en_US.UTF-8"

мой пример исходного файла (хранится в кодировке UTF-16BE):

// main.cpp:

#include <iostream>

int main()
{
    std::cout << "Hello, UTF-16" << std::endl;
    return 0;
}

мой шаги:

  • Я прочитал руководство g++ о опции-finput-charset. руководство g++ говорит:

- finput-charset=charset Установить входной набор символов, используемый для перевода из набора символов входного файла в исходный набор символов, используемый ССЗ. Если языковой стандарт не указан или GCC не может получить это информация из локали,значение по умолчанию-UTF-8. Это может быть переопределяется параметром locale или командной строки. В настоящее время параметр командной строки имеет приоритет, если конфликт. charset может быть любой кодировкой, поддерживаемой системой "iconv" обычной библиотеке.

  • таким образом, я ввел команду следующим образом:

g++ - finput-charset=UTF-16BE main.cpp

и я получил эти ошибки:

в файл в комплекте с основной.cpp: 1:

в/usr/lib в/ССЗ/для i386-RedHat это-линукс/4.1.2/../../../../ включить/c++ / 4.1.2 / iostream:1: ошибка: stray '342 ' в программе

в/usr/lib в/ССЗ/для i386-RedHat это-линукс/4.1.2/../../../../ включить/c++ / 4.1.2 / iostream:1: ошибка: stray '274 ' в программе

...(неоднократно, много, около 4000+)...

в/usr/lib в/ССЗ/для i386-RedHat это-линукс/4.1.2/../../../../ включить/c++ / 4.1.2 / iostream:1: ошибка: stray '257 ' в программе

main.cpp: в функции ' int main()’:

main.cpp: 5: ошибка: 'cout’ не является членом 'std'

main.cpp: 5: ошибка: "endl" не является членом "std"

  • текст руководства предполагает, что кодировка может быть любой кодировкой, поддерживаемой подпрограммой "iconv", поэтому я предположил, что ошибки компиляции могут быть вызваны моей библиотекой iconv. Затем я проверил iconv:

С iconv -- from-code=UTF-16BE --to-code=UTF-8 --output=main_utf8.cpp main.cpp

A " main_utf8.cpp " файл генерируется, как и ожидалось. Затем я попытался скомпилировать его:

g++ - finput-charset=UTF-8 main_utf8.cpp

обратите внимание, что я явно указал кодировку ввода, чтобы увидеть, сделал ли я что-нибудь неправильно, но на этот раз "a.out " был сгенерирован без каких-либо ошибок. Когда я запустил его, он мог произвести правильное выход.

наконец-то...

Я не мог понять, где я сделал неправильно. Я искал в интернете, пытаясь найти некоторые примеры для этого параметра компилятора, но я не мог.

пожалуйста, посоветуйте! Спасибо!

дальнейшие правки:

Спасибо, ребята! Ваши ответы быстры! Некоторые обновления:

  1. когда я сказал "UTF-16", я имел в виду"UTF-16 + BOM". На самом деле я использовал UTF-16BE. Я обновил текст выше.
  2. некоторые ответы сказать ошибки вызваны не-UTF-16 заголовочных файлов. Вот мои мысли, если это так: мы всегда будем включать некоторые стандартные файлы заголовков при написании проекта C/C++, верно? Например, stdio.h или iostream. Если компилятор G++ имеет дело только с кодировкой исходных файлов, созданных нами, но никогда с исходными файлами в стандартной библиотеке, то для чего существует эта опция-finput-charset??

окончательная правка:

наконец, мое решение, как это:

  1. в начале я изменил кодировку своих исходных файлов на GB2312, как сказал" мистер Листер " ниже. Некоторое время это работало нормально, но позже я нашел, что это не подходит для моей ситуации, потому что большинство других частей системы все еще используют UTF-8 для связи и интерфейсов, поэтому я должен преобразовать кодировку во многих местах... Не только издержки моей работы, это также может привести к некоторому снижению производительности в моей программе.
  2. позже я попытался преобразовать все мои исходные файлы в UTF-8 + BOM. Таким образом, Visual Studio в Windows может скомпилировать их с удовольствием, но GCC в Linux будет жаловаться. Затем я написал сценарий оболочки для удаления спецификации, и прежде чем я хочу скомпилировать свой код с GCC, я сначала запускаю этот сценарий.
  3. К счастью, мне не нужно создавать код в Linux вручную, потому что TeamCity инструмент непрерывной интеграции используется в моем проекте для автоматического создания сборки. Я мог бы изменить шаги сборки в TeamCity, чтобы помочь мне работать этот сценарий перед началом ежедневной сборки.
  4. С этой кодировке UTF-8 + спецификации + скрипт способ, я решил не редактировать исходный код в Linux, потому что если я хочу делать так, я должен убедиться, что мой код может построить успешно, прежде чем я совершить это, что означает, что я должен запустить сценарий, чтобы удалить BOM, прежде чем я построить код, что означает, что СВН будет отчитываться каждый файл изменен(спецификации удален), таким образом, сделать его очень легко совершить по ошибке не тот файл. Чтобы решить эту проблему, я написал другой сценарий оболочки для добавьте спецификацию обратно в исходные файлы. Хотя я все еще не очень часто редактирую свой код в Linux, но когда мне действительно нужно, мне не нужно сталкиваться с ужасно длинным списком изменений в диалоговом окне фиксации.

4 ответов


Кодировка Блюз

вы не можете использовать UTF-16 для файлов исходного кода; потому что заголовок, который вы включаете,<iostream>, не кодируется UTF-16. As #include включает файлы дословно, это означает, что у вас внезапно есть файл с кодировкой UTF-16 с большим куском (примерно 4k, по-видимому) недопустимых данных.

почти нет веских причин когда-либо использовать UTF-16 для чего-либо, так что это так же хорошо.

Edit: по поводу проблемы с поддержкой кодирования: сами ОС не несут ответственности за обеспечение поддержки кодирования, это сводится к используемым компиляторам.

g++ в Windows поддерживает абсолютно все те же кодировки, что и g++ в Linux, потому что это одна и та же программа, если любая версия g++, которую вы используете в Windows, не зависит от глубоко сломанной библиотеки iconv.

Проверьте ваш набор инструментов и убедитесь, что все ваши инструменты находятся в рабочем состоянии.

как альтернатива; не используйте китайский язык в исходных файлах, но пишите их на английском языке, используя англоязычные литералы, или просто TOKEN_STYLE_PLACEHOLDERС помощью l10n и i18n чтобы заменить их в исполняемом файле.

Threedit: -finput-charset почти наверняка является пережитком со времен кодовых страниц и другой ерунды такого рода; однако; файл ISO-8859-n почти всегда будет совместим со стандартными заголовками UTF-8, однако см. reedit ниже.

Reedit: В следующий раз запомните простую мантру: "Н'ДУУ!"; "Никогда не используйте UTF-8!"


как i18n

общим решением такого рода проблемы является полное устранение проблемы, например,gettext.

при использовании gettext вы обычно получаете функцию loc(char *) это абстрагирует большую часть конкретного кода инструмента перевода. Итак, вместо

#include <iostream>

int main () {
  std::cout << "瓜田李下" << std::endl;
}

вы хотели есть

#include <iostream>

#include "translation.h"

int main () {
  std::cout << loc("DEEPER_MEANING") << std::endl;
}

и zh.po:

msgid DEEPER_MEANING
msgstr "瓜田李下"

конечно, вы также можете иметь en.po:

msgid DEEPER_MEANING
msgstr "Still waters run deep"

это можно расширить, и пакет gettext имеет инструменты для расширения строк с переменными и такими, или вы можете использовать printf, для учета различных грамматик.


Третий Вариант

вместо того, чтобы иметь дело с несколькими компиляторами с различными требованиями к кодировкам файлов, окончания файлов, метки порядка байтов и другие проблемы такого рода; можно скомпилировать с помощью MinGW или аналогичные инструменты.

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


в сообщении об ошибке говорится, что проблема находится в добавить файлы поэтому я предполагаю, что файлы include являются нормальными UTF-8, но компилятор хочет рассматривать их как UTF-16 из-за переключателя компилятора.

поэтому я боюсь, что решение заключается в том, чтобы всегда сначала преобразовать источник в UTF-8; возможно, в makefile. Или найти решение, которое не содержит файлов include в других кодировках...

Edit: Возможно, кодировка GB работайте, если и только если ни один из системных исходных файлов не содержит символов, отличных от ASCII. Тогда вы могли бы сказать компилятору, что они были закодированы GB без проблем.


Это не работает, потому что компилятор также попытается прочитать заголовочные файлы как UTF-16, которыми они не являются.


UTF-16 с не кодировка для байтов. Это кодировка, в которой ваш базовый блок хранения составляет 16 бит.

Если вы хотите сохранить UTF-16 в последовательности байтов, вам нужно выбрать между UTF-16BE и UTF-16LE.