Про gcc и кодировки

Прочитав статью про создание самодельных шрифтов вспомнил про свои мучения. Правда, у меня проблема возникла в тот момент, когда я зашил созданный шрифт и попытался вывести с помощью AVR-ки русские строки, то есть, с кодировками utf-8/win-1251. Про них и пост.

Задача
Есть AVR и желание выводить с его помощью русские строки.
Есть gcc в качестве компилятора, работающий под виндой.
Нет желания городить свою библиотеку для работы с utf-8.
Спрашивается: как?
Сначала я сделал как в VC++: открыл любимый блокнотик, забил туда win-1251, сама строка была задана вот так:


char s[] = {"Тестовая строка"};


Собрал, запустил… мимо.
Ок, пошёл в гугл.
Нашёл страничку.
Поставил опциями компилятора win-1251 на входе и выходе.
Всё сломалось с криком:

"cc1plus.exe: error: no iconv implementation, cannot convert from win-1251 to UTF-8".

Ну, примерно с таким криком.
Дальше я долго гуглил, выяснил таки, что проблема в том, что в винде нет волшебного iconv (libiconv), который есть в линуксе, и что эта самая либа должна быть статически влинкована в gcc.
Нашёл адский тредик, как мужики пытались это сделать.
И наконец таки нашёл страничку с уже готовым gcc.
Ура. Скачал. Обновил.
Дальше просто. Сначала нужно взять свои исходники и сконвертить их в utf-8. На всякий случай. Может и без этого заработает.
Потом поправить строчку с ключиками от gcc:

C:\tools\avr-gcc\bin\avr-g++.exe -mmcu=atmega8515 -finput-charset=UTF-8 -fexec-charset=cp1251 -std=gnu++11 -Os main.cpp -o main.o

Потом запустить сборку, и вдумчиво посмотреть в полученный бинарник.
Дальше открываем .hex файл и убеждаемся, что в нём появились вполне нормальные ASCII коды, которые похожи на строку в win-1251!
Profit!

ЗЫ: Да, найденная сборка gcc имеет одну неприятную особенность: внутри она содержит неправильный avr-size, который не понимает ключик mmcu.

Комментарии (28)

RSS свернуть / развернуть
А ещё лучше не сувать русских строк в код, а пихать их отдельным файлом и вставлять define'ом
А самый верх навыка джедая — делать массив строковых констант и заполнять его из файла линковщиком. Но это сложно. Зато позволяет не только русский текст, но и картинки bmp, файлы wav и прочие ресурсы пихать.
0
  • avatar
  • dekar
  • 10 февраля 2016, 18:27
Мне кажется, что вставить что-либо из внешнего файла можно include-ом. А не define-ом.
Кроме того, препроцессор (обрабатывающий include/define/etc) работает до компилятора. А значит компилятору всё равно придётся как-то рассказать, какая у входного файла кодировка.
Про линковщик. Я не знаю способа, как заставить AVR/gcc прочитать чего-нибудь из бинаря. Ну, кроме функции pgm_read_byte. Но этой функции надо дать адрес. А адресами ведает компилятор, а не линковщик. (Ну, точнее сказать, узнать адрес проще с помощью компилятора, а не линковщика).

Вообще, массивы строк, битмапки и т.п. действительно стоит хранить как-то отдельно. Но это лучше делать под полноценной ОСью, которая умеет что-то читать из биинарника (например, в винде есть набор функций, которые читают из ресурсов иконки/строки), плюс, это стоит делать для сравнительно больших проектов, которые требуют специфики: например, если надо сделать локализацию приложения, то можно действительно подключить разные ресурсы с разными строками.

У меня же есть мелкий микроконтроллер и прошивка. ОСи нет. Ресурсов нет. Функций чтения из файлов нет. Нет даже файловой системы :)
0
Коппилятор оперирует ссылками, вот как раз адреса узнает линковщик.
+1
В случае gcc — он и компилятор, и линковщик.
0
И что с того?
0
Вообще-то, в составе GCC линковщика нет вообще. Он в составе binutils.
0
Вообще-то линкер заточен под таргет платформу. Линкер входит в тулчейн GCC.
0
Линкер входит в тулчейн наряду с GCC, а не в составе оного.
0
Я не знаю способа, как заставить AVR/gcc прочитать чего-нибудь из бинаря.

Ну это не значит что его нет, лишь то что ты плохо знаешь gcc. Речь не о загрузке файлов в рантайме, а о статической влинковке данных.
0
Ну это не значит что его нет, лишь то что ты плохо знаешь gcc.
Да, это так. Послушаю твои варианты.

Речь не о загрузке файлов в рантайме, а о статической влинковке данных.
Вообще-то ты процитировал меня. И я точно знаю, что я хотел сказать про рантайм :)

Короче, нету в avr+gcc функций вида LoadLibrary/fopen/etc. Ну, то есть, можно написать свой вариант, который будет делать любую фантазию, а-ля «файловая система поверх флеша AVR-ки», но «из коробки» ничего такого нет.
0
Короче, нету в avr+gcc функций вида LoadLibrary/fopen/etc.
avr-gcc — это компилятор, причём тут функции ОС? Зачем разводить огороды с файловыми системами если нужно всего лишь обратиться к блоку данных во флеше? Проще всего сунуть его линковщику в виде объектного файла и спокойно потом обращаться по символам. Скорее всего есть и другие способы, но уже придётся ковырять мейкфайл и лд-скрипт, чего лучше избегать дабы не потонуть во всём этом линупсовом болоте.
0
причём тут функции ОС?
Притом, что обычно функции перекодирования строк находятся в ОС. А доступ к ОС осуществляется через API, который доступен из компилятора. Но ОСи у нас нет. Приходится выкручиваться.

Проще всего...
Да, наверное проще.
Но лично мне проще всего сунуть обычную человеко-читаемую строку в исходный код. И не прыгать с бубном вокруг линкера.

… дабы не потонуть во всём этом линупсовом болоте.
Справедливости ради, gcc и вокруг — это и есть линуксовое болото, которое зачем-то притащили в винду.
0
Но лично мне проще всего сунуть обычную человеко-читаемую строку в исходный код.
Это ежу понятно, что проще. Все так и делают. Меня возмутило лишь то сунуть бинарь в флеш и обратиться к нему — якобы невесть какая проблема и нужно городить фс.
0
define определяет макросы, include — вставляет файл.
Бинарный файл нельзя просто так скормить ни компилятору, ни линкеру. Прийдется его превратить в массив вида uint8_t array[]= {0x1, 0x2...'} какой-нибудь утилитой, а потом уже вставлять в код программы. Утилит есть масса готовых, да и самому такую сделать можно за пол-часа…
0
Пардон, забыл совсем. На самом деле можно сделать объектный файл из бинарного с помощью
ld -r -b binary file.bin -o file.o, ну и потом уже собрать всё вместе. Обращаться нужно к с переменными _file_start _file_end и _file_size объявив их как extern. Всегда можно подсмотреть objdump-ом если забудете (objdump -t file.o).
Когда-то добавлял так блобы с fpga имиджами в бинарь микроконтроллера.
0
avr-objcopy -I binary -O elf32-avr --rename-section=.data=.text test.bin test.o

extern uint8_t const _binary_test1_bin_start[];
extern uint8_t const _binary_test1_bin_end[];

memcpy_P(buf, _binary_test1_bin_start, count);
можно как-то так
0
Объектный файл подключить к линковке просто через студию, Configuration -> Libraries -> Add object
0
По теме. Конвертируйте строку в массив байтов
char s[]={0x10, 0x20, 0x00};
Для конвертирования можно написать небольшую программку, например на python3:
text = 'наш текст'
ba = text.encode('cp1251') #или укажите другую кодировку
tout ='char s[] = {'
for b in ba:
  tout += hex(b) + ','
tout += '0x00};'
print(tout)
0
Да, можно и так. Может так даже и хорошо.
Но это вынуждает тащить ещё и питон. И снижает читаемость исходного кода.

ЗЫ: В общем, везде приходится искать компромиссы. И результат будет у всех разный :)
0
Почему не использовать нативные средства GCC?
0
>> Но это вынуждает тащить ещё и питон.…
Напрягает, если к IDE приходится искать и приколхозивать сторонние подпрограммы…
0
Ну если уж так хочется русских текстов… лучше, конечно, работать в *nix системе — там проблем нет никаких, а в винде — сплошные костыли.
0
В винде сплошные костыли в программах, приехавших с юникса. Хотя GCC еще приличный.
0
Под винду нет нормальных компиляторв за вменяемые деньги, неприехавших из юникса. Или несколко тысяч $ плати, или gcc на костылях.
0
Под винду нет нормальных компиляторв за вменяемые деньги, неприехавших из юникса. Или несколко тысяч $ плати, или gcc на костылях.
Насколько я понимаю, есть как минимум две бесплатные альтернативы: простейшие и бесплатные варианты Visual Studio и приползший с яблока clang.
Но это именно про winapi.
Если речь про AVR, то тут не очень понятно. gcc бесплатный, а про всё остальное я вообще не в курсе.
0
Я кросс-компиляторы имел ввиду. Для самой винды есть бесплатный vc toolkit.
0
Это да. Я и сам GCC пользую для С/С++. Хотя под таргеты Win32/Win64 еще можно что-то найти, бесплатная VS вполне неплоха.
0
а в винде — сплошные костыли
Ничего не могу сказать про никсы, но вот в винде с кодировками всё хорошо. Начиная с w2k вкручена поддержка Unicode, причём прям в ядро. И все функции принимают широкие строки (есть парные функции, которые принимают ascii).
Другое дело, что поверх винды есть ещё и инструментарий, а-ля компиляторы. И там накладывается небольшой слой проблем вида «а как бы зашить строки в исходники». Есть на эту тему отличная статья.
Но на костыли это не очень похоже. И да, в контексте исходного поста — сборка под AVR в винде — это всё же кросс компиляция. Приходится приспосабливаться.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.