8/07/2009
Поисковик по научным работам.
И кроме традиционных arxiv.org и ieee.org, последний к тому же платный, я для себя открыл бесплатный и очень удобный поисковик citeseerx.ist.psu.edu, на котором можно найти очень много всего интересного.
Думаю кому-нибудь пригодится.
Embedded Linux Conference
Есть что послушать и есть чего почитать.
Смотреть тут: http://free-electrons.com/blog/elc-2009-videos/
7/25/2009
Дефрагментация xfs
И о ужас, он оказался 86 %. Страшная цифра. Но обо всем по порядку.
Чтобы посмотреть какое устройство у вас куда примонтировано нужно в консоли набрать команду mount без параметров.
Для того чтобы посмотреть, каков уровень фрагментации файлов на разделах с файловой системой xfs, нужно установить программы xfs_db и xfs_fsr. Находятся они в пакетах xfsprogs и xfsdump соответственно.
Устанавливаем:
emerge sys-fs/xfsdump sys-fs/xfsprogs
Теперь чтобы посмотреть уровень фрагментации нужно запустить программу xfs_db -r /устройство
например:
xfs_db -r /dev/sda3
и далее в появившейся консоли набрать команду frag
xfs_db> frag
Примерно такого содержания может оказаться ее вывод:
actual 170812, ideal 22388, fragmentation factor 86.89%
И это есть не очень хорошо.
Жмем q чтобы выйти.
Чтобы запустить дефрагментацию набираем
xfs_fsr -v /dev/sda3
и ждем.
Вот так.
6/14/2009
QtAda Examples
Рад сообщить вам о начале проекта по портированию Qt примеров с языка C++ на язык
Ada.
В настоящий момент полностью реализовано 5 примеров.
Адрес проекта : https://sourceforge.net/projects/qtada/
Все желающие могут присоединиться.
P.S. Для вас это отличная возможность изучить и Qt и Аду.
6/08/2009
Релиз QtAda 3.0
Вышла версия 3.0.0 библиотеки QtAda.
В этом релизе исправлено много ошибок, добавлена поддержка новых классов.
А также проведена большая работа по упрощению использования.
Системные требования:
- компилятор - gnat gpl 2009
- семантический анализатор asis-gpl-2009
- библиотека qt-4.5.1
5/28/2009
Вышел Gnat GPL 2009
Скачать можно на оффициальном сайте.
Компилятор полностью поддерживает стандарт Ады 2005.
И в скором времени только им можно будет скомпилировать QtAda.
UPD: С новым компилятором не нужно выполнять никаких сложных действий для того чтобы установить QtAda. Только после установки QtAda нужно лишь указать компилятору как использовать Amoc. И все.
Ну и естественно прописать все необходимые пути.
5/21/2009
Установка и настройка QtAda
В этой статье, я хочу вам рассказать как скачать и установить библиотеку Qtada.
Qtada - это библиотека, которая позволяет создавать графический интерфейс пользователя на языке Ада, с использованием возможностей библиотеки Qt.
Для того чтобы установить QtAda понадобится установить и настроить :
- Компилятор языка Ада (gnat)
- Библиотеку для семантического анализа программ на Аде (asis)
- Библиотеку Qt, версии не ниже 4.5.0
- Библиотеку QtAda версии 3.x
1. Компилятор:
QtAda написана с использованием языка Ада стандарта 2005 года. Компилятор Gnat от компании AdaCore наиболее полно поддерживает стандарт Ады 2005, и позволяет без проблем скомпилировать библиотеку. Для установки QtAda нужно использовать Gnat GPL 2008 - самую последнюю версию на данный момент, доступную для некоммерческого использования. Скачать компилятор можно с официального сайта www.adacore.com или же с одного из зеркал. Размер компилятора около 90 мегабайт.
Я качал Gnat с зеркала на сайте ftp.mipt.ru :
cd /tmp/ && wget -c ftp://ftp.mipt.ru/ada/gnat-gpl-2008/x86_64-linux/gnat-gpl-2008-x86_64-pc-linux-gnu-bin.tar.gz
Распаковываем во временную папку:
cd /tmp/ && tar xfv gnat-gpl-2008-x86_64-pc-linux-gnu-bin.tar.gz
Перемещаем распакованную папку в /opt/gnat/:
mv /tmp/gnat-2008-x86_64-pc-linux-gnu-bin /opt/gnat
Пол-дела сделано.
Теперь, чтобы воспользоваться компилятором, нужно прописать в переменных окружения пути к исполняемым файлам и библиотекам. Для этого проще всего создать в домашнем каталоге файл ~/.ada_rc примерно следующего содержания:
export PATH=/opt/gnat/bin:$PATH
export LD_LIBRARY_PATH=/usr/lib64/gcc/x86_64-pc-linux-gnu/4.2.4/:/opt/gnat/lib/gcc/x86_64-pc-linux-gnu/4.1.3/adalib/:$LD_LIBRARY_PATH
Далее по необходимости, можно каждый раз набирать в консоли source ~./ada_rc или же прописать эту строчку в файле ~/.bashrc
Пути к компилятору обязательно должны быть первыми в обоих переменных окружения. Это нужно по следующей причине: скорее всего ваш системный GCC не скомпилирован с поддержкой языка программирования Ада, и поэтому он не сможет запустить компилятор gnat. По этой причине, вместе с gnat'ом поставляется своя версия gcc, которая умеет делать все что нужно.
Следующий шаг выполнять НЕ НУЖНО, если версия вашего системного gcc старше или такая же как и версия gcc,предоставляемого gnat'ом (в данном случае 4.1.2)
Если же у вас в системе компилятор новее, то gcc, который входит в состав gnat, может
работать некорректно, из за конфликтов своих библиотек с системными, а конкретно библиотеки, libgcc_s.so.1
Нужно удалить библиотеку поставляемую вместе с gnat:
rm -i `find /opt/gnat/ -name libgcc_s.so.1`
и сделать символическую ссылку на системную:
ln -s /usr/lib64/gcc/x86_64-pc-linux-gnu/4.3.3/libgcc_s.so.1 /opt/gnat/lib64/
Теперь можно со спокойной душой набрать в консоли
gnatls -v
и убедиться что компилятор работает.
Вывод должен быть примерно следующим:
GNATLS GPL 2008 (20080521)
Copyright (C) 1997-2008, Free Software Foundation, Inc.
Source Search Path:
/usr/lib64/gnat-gpl/x86_64-pc-linux-gnu/4.1-2008/adainclude/
/opt/gnat/lib/gcc/x86_64-pc-linux-gnu/4.1.3/adainclude/
Object Search Path:
/usr/lib64/gnat-gpl/x86_64-pc-linux-gnu/4.1-2008/adalib/
/opt/gnat/lib/gcc/x86_64-pc-linux-gnu/4.1.3/adalib/
Project Search Path:
/opt/gnat/lib/gnat/
2. Установка ASIS
ASIS - это Спецификация Семантического Интерфейса к языку Ада (Ada Semantic Interface Specification, ASIS). Он необходим для корректной работы компилятора мета информации, поставляемого с QtAda'ой.
Скачать ASIS можно там же где и компилятор:
cd /tmp && wget -c ftp://ftp.mipt.ru/ada/gnat-gpl-2008/x86_64-linux/tools/asis/asis-gpl-2008-src.tgz
Затем его надо распаковать:
tar xfv asis-gpl-2008-src.tgz
Перейти в каталог с исходниками:
cd asis-2008-src
Скомпилировать:
make INSTALL_DIR=/opt/gnat
Установить:
make INSTALL_DIR=/opt/gnat install
Теперь нужно убедиться, что ASIS установлен корректно, и QtAda при компиляции обнаружит проектный файла библиотеки ASIS. Для этого проверьте, есть ли файл asis.gpr в дирректории /opt/gnat/lib/gnat/
Если есть, то все хорошо, и можно продолжать дальше. Если нет, то что-то не так.
3. Установка Qt.
Qt - это кросс платформенная библиотека для создания графического интерфейса пользователя.
Скачать можно с сайта www.trolltech.com.
Процесс установки Qt я здесь описывать не буду.
Замечу лишь, что при конфигурации Qt убедитесь, что библиотека сконфигурирована БЕЗ флага -no-accessebility
4. Установка QtAda
Если ваш системный компилятор новее, чем тот, что идет в составе Gnat, то перед установкой QtAda нужно чуть чуть сконфигурировать компилятор, дабы корректно откомпилировать ту часть проекта, которая написана на C++.
Сначала узнаем версию системного компилятора:
/usr/bin/gcc -v
Из полученного вывода нужна самая последняя строка. В моем случае она выглядит так:
gcc версия 4.3.3 (Gentoo 4.3.3-r2 p1.1, pie-10.1.5)
Из этой строки нам понадобится только Gentoo 4.3.3-r2.
Открываем в вашем любимом текстовом редакторе файл compilers.xml :
emacs /opt/gnat/share/gprconfig/compilers.xml
Находим там блок, который начинается с комментария <!-- GCC 3.x & 4.x -->
и заменяем в строке <grep regexp="\(GCC\) (\S+)" group="1">
выражение \(GCC\) на (Gentoo\ 4.3.3-r2)
Далее ищем блок, который начинается с комментария <!-- G++ compilers --> и проделываем те же самые манипуляции.
Для окончательной конфигурации компилятора нужно выполнить:
gprconfig
В результате чего в консоли появится вот такой список:
--------------------------------------------------
gprconfig has found the following compilers on your PATH.
Only those matching the target and the selected compilers are displayed.
(A) GNAT for Ada in /opt/gnat/bin/ version 2008 (default runtime)
(B) GNAT for Ada in /opt/gnat/bin/ version 2008 (native runtime)
(C) GNAT for Ada in /opt/gnat/bin/ version 2008 (sjlj runtime)
(D) GCC-ASM for Asm in /opt/gnat/bin/ version 4.1.3
(E) GCC-ASM for Asm2 in /opt/gnat/bin/ version 4.1.3
(F) GCC-ASM for Asm_Cpp in /opt/gnat/bin/ version 4.1.3
(G) GCC for C in /usr/bin/ version Gentoo 4.3.3-r2
(H) G++ for C++ in /usr/bin/ version Gentoo 4.3.3-r2
Select or unselect the following compiler (or "s" to save):
Нажимаем A, <enter>, D, <enter>, E <enter>, F <enter>, G <enter>, H <enter>
Возле каждого выбранного пункта должна появиться *.
Жмем s и сохраняем настройки.
Теперь все готово для компиляции QtAda.
Хочу отметить, что все вышеперечисленные действия нужно выполнять, если у ваш системный компилятор новее того, что поставляется вместе с gnat.
Качаем QtAda с официального сайта:
cd /tmp && wget -c http://download.qtada.com/qtada-gpl-3.0.0-20090423-3303.tar.gz
распаковываем архив:
cd /tmp && tar xfv qtada-gpl-3.0.0-20090423-3303.tar.gz
заходим в директорию с исходниками:
cd qtada-gpl-3.0.0-20090423-3303
Конфигурируем && компилируем && устанавливаем:
./configure -prefix=/opt/qtada && make && make install
После установки нужно обновить переменные окружения PATH и LD_LIBRARY_PATH:
export PATH=/opt/qtada/bin:$PATH
export LD_LIBRARY_PATH=/opt/qtada/lib:$LD_LIBRARY_PATH
Затем нужно указать компилятору где искать файл проекта QtAda.
Для этого нужно установить переменную окружения ADA_PROJECT_PATH:
export ADA_PROJECT_PATH=/opt/qtada/lib/gnat/
Все установки переменных окружения неплохо прописать в файл ~/.ada_rc
Еще необходимо сказать компилятору о том как, использовать amoc. Для этого создадим символическую ссылку:
ln -s /opt/qtada/share/gprconfig/amoc.xml /opt/gnat/share/gprconfig/
и обновим настройки компилятора:
gprconfig
Опять выбираем все нужные компиляторы, включая вновь появившийся Amoc.
Сохраняем.
Теперь QtAda установлена и готова для использования.
5/17/2009
Как Вставить много одинаковых символов в Emacs'е
Например :
Ctrl + 1 + 0
Затем если нажать на '+',
то начиная от текущей позиции курсора появится 10 символов '+'
4/29/2009
Установка и настройка XMPP сервера ejabberd
В голове сразу мелькнула мысль поставить джаббер сервер. Почитав форумы, обзоры и прочее я выбрал ejabberd
Ну что сказать, не сервер, а сказка. Скачал, распаковал, проинсталлил и все сразу заработало.
Остановимся на пункте "проинсталлил".сначала как всегда: скачал исходники, начал с configure, а он требует erlang чтоб скомпилиться.
ну, думаю, нет, проходили. Сначала erlang ему, а потом еще пол мира. Качаю готовый .bin файл.
Запускаю и наслаждаюсь: спросил куда ставить, как запускать, кто админ, какой пароль, какой виртуальный хост, ну вообщем все что нужно.
В итоге у меня в /opt/ лежит легковесный, простой в настройке XMPP сервер со своей безой данных (Mnesia), с веб-интерфейсом (указываем порт 5280) и с кучей пользователей.
Настройка заключалась в том, что нужно было организовать общий ростер для всех. а то как начнется авторизация, так хоть комп не включай. Почитав форум на официальном сайте я нашел. Все оказалось очень просто. Открываем веб панель управления -> виртуальные хосты -> "имя_хоста" -> группы общих контактов -> и тет создаем новую группу, назовем ее all (или кому как захочется). После ее создания открываем и пишем:
название - all , описание - группа для всех, члены - @all@ , видимые группы - all. Как вы догадались все дело в пункте "члены". Здесь можно указывать либо каждого пользователя отдельно (user@host admin@host), либо @all@ для всех. Так же хочу попробовать в дальнейшем разбить пользователей на меньшие группы и перепробовать это дело для пункта "видимые группы".
Еще один момент - программу велено было поставить не всем, а только руководителям. Ну а как то обижать ребят, с которыми общаться куда приятнее нежели с руководителями, не хотелось. Выход нашелся! создаем еще один виртуальный хост и по такой же схеме регистрируем всех там. Правда, как сделать это через веб-интерфейс я не нашел, поэтому вручную в конфиге в секции hosts дописал еще один виртуальный хост.
В качестве клиента выбрал Psi - просто потому что он самый распространенный. При подключении клиент выдал мне что ему не нравится сертификат. ну что ж, будем делать новый. После установки сертификаты были, но я решил их переделать:
openssl req -new -x509 -newkey rsa:1024 -days 3650 -keyout privkey.pem -out server.pem
openssl rsa -in privkey.pem -out privkey.pem
cat privkey.pem >> server.pem
После этого скопировал server.pem в папку %program files%/Psi/certs и установил его.
4/27/2009
Поиск по истории команд в bash
1. Жмем в терминале Ctrl+R и начинаем набирать текст, который хотим найти.
Если совпадений несколько, то для перебора можно использовать стрелки вверх, вниз и клавиши PageUp и PageDown.
2. Сначала пишем начальные символы текста, который хотим найти, затем перебираем варианты нажимая клавиши PageUp, PageDown.
3. Команда history | grep текст_для_поиска. Тут я думаю все понятно.
4/21/2009
Учим Linux запускать exe файлы.
Однако, не составляет труда обучить ядро Linux запускать любые другие исполняемые файлы (.exe файлы для Windows, скрипты на shell, python, байткод java и т.д.) без явного указание эмулятора Т.е. в командной строке можно просто написать ./notepad.exe или ./my_script.py.
Для этого нужно обеспечить ядро необходимой информацией о формате исполняемого файла, и о том, каким образом и с помощью чего его можно интерпретировать.
Что для этого нужно?
1. Для этого нужно включить в ядре поддержку остальных исполняемых форматов:
В секции Executable file formats / Emulation-->
Опция

Можно или встроить эту возможность в ядро, или оформить ее в качестве отдельного модуля. Модуль будет называться binfmt_misc.
2. Подмонтировать файловую систему binfmt_misc в каталог /proc:
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
3. Перейти в каталог /proc/sys/fs/binfmt_misc. У вас тут должно лежать два файла: register и status
4. Описать формат и интерпретатор для этого формата:
Для того что зарегистрировать новый формат исполняемого файла и интерпретатор для него нужно добавить в файл register строку в формате:
:name:type:offset:magic:mask:interpreter:flags
Вот что значат приведенные поля:
- 'name' - строковый идентификатор. В каталоге /proc/sys/fs/binfmt_misc будет создан новый файл с именем name
- 'type' - способ распознавания. Может быть 'M' для волшебства и 'E' для расширения.
- 'offset' - смещение маски в файле,считается в байтах. Этот параметр по умолчанию равен 0, если вы его не указываете (например: ':name:type::magic...')
- 'magic' - последовательность байт для соответствия которой и определяется binfmt_misc. Строка поля magic может содержать шестнадцатириные символы, такие как \x0a или \xA4.
- 'mask' маска (опциональна, по умолчанию имеет значение 0xff) . Добавляя строку как в поле magic и такой же длины, вы можете маскировать соответствие некоторых битов файла.
- 'interpreter' - программа, которая должна быть выполнена вместе с исполняемым фалйлом, как первый аргумент (Необходимо указывать полный путь)
- 'flags' - опциональное поле, которое контролирует нектороые аспекты вызова интерпретатора
':DOSWin:M::MZ::/usr/bin/wine:
Вот так:
echo ':DOSWin:M::MZ::/usr/bin/wine:' > register
Теперь в каталоге /proc/sys/fs/binfmt_misc у нас появился файл DOSWin следующего содержания:
$bash: cat DOSWin
enabled
interpreter /usr/bin/wine
flags:
offset 0
magic 4d5a
После всего этого в командной строке можно написать ./notepad.exe и у вас запустится notepad с помощью wine'a.
5. Для того, чтобы binfmt_misc не пришлось монтировать каждый раз вручную, в /etc/fstab можно добавить вот такую строчку:
none /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0
6. Для того, чтобы отключить интерпретацию формата, нужно записать 0 в появившийся файл:
7. Для того чтобы удалить формат, нужно записать -1 в имя файла этого формата:
echo -1 > DOSWin
4/17/2009
Вставка пары скобок в Emacs
скобки, вставляется не только открывающая скобка, но и закрывающая.
Для того, чтобы добавить такую возможность в Emacs, нужно прописать в конфиг файле
вот такие строки:
(defun insert-second-hook ()
(interactive)
(insert "()")
(goto-char (- (point) 1)))
(global-set-key (kbd "\(") 'insert-second-hook)
Что здесь происходит:
в 1-й строке объявляем функцию insert-second-hook ().
во 2-й строке говорим, что она используется в интерактивном режиме.
в 3-й строке вставляем в активный буфер пару скобок '()'
в 4-й строке помещаем курсор между скобками.
в 5-й строке вешаем хук на клавишу '('
Вот и все.
4/16/2009
VirtualBox VDI to qemu qcow
Делается это по следующей схеме:
VDI ------> RAW Image ------> QCow.
1. Конвертируем из VDI в Raw Image:
VBoxManage internalcommands converttoraw vbox_image.vdi image.raw
2. Конвертируем их RAW Image в QCow:
qemu-img convert -f raw image.raw -O qcow2 image.qcow
Вуаля.
4/09/2009
4/03/2009
Amd Catalyst и KDE 4
Наконец-то недавно вышел релиз драйвера ATI AMD Catalyst за версией 9.3
И видимо товарищи из AMD все таки сподобились починить работу своего поделия на многоядерных машинах.
KDE4 у меня уже работает целый день, а Linux до сих пор не упал.
Всем качать и обновляться.
P.S. Несмотря на все вышесказанное, я являюсь поклонником NVIDIA
3/16/2009
Поиск утечек памяти штатными средствами.
На помощь нам приходит glibc и функции mtrace и muntrace. Функция mtrace устанавливает обработчики для malloc, realloc, и free. А функция muntrace убирает установленные обработчики.
Для того чтобы установить обработчики, нужно вызвать mtrace скажем в начале программы. Затем нужно определить переменную окружения MALLOC_TRACE в которой нужно определить путь к текстовому файлу, где mtrace сохранит результаты работы.
Рассмотрим пример:
1 #include <mcheck.h>
2 #include <stdlib.h>
3
4 int main (int argc, char *argv[])
5 {
6 int *i = NULL;
7
8 mtrace ();
9 i = (int*)malloc (sizeof (int));
10
11 return 0;
12 }
В функции утечка памяти: в строке 9 она выделяется, но далее нигде не освобождается.
Компилируем программу с отладочной инорфмацией, если мы хотим увидеть не только адрес функции, но еще и номер строки:
Устанавливаем в переменной окружения
export MALLOC_TRACE=/tmp/out.txt
Запускаем программу:
./main
После запуска можно посмотреть на созданный файл:
cat /tmp/out.txt
Содержимое его будет примерно таким:
= Start
@ ./main:[0x40057e] + 0x602460 0x4
Не очень понятно, что тут и зачем =).
Однако вместе с libc ставится и скрипт на языке perl, который выводит информацию об утечке памяти в более человеческом виде. Запускаем в консоли:
mtrace ./main /tmp/out.txt
И получаем вывод:
Memory not freed:
-----------------
Address Size Caller
0x0000000000602460 0x4 at /tmp/main.c:9
P.S. Не забываете очищать выделенную память, а если вы не забываете ее очищать, то и не забывайте ее ранее выделять ;-)
2/15/2009
KDE4 и Alsa
Я вот тоже решил не отставать от продвинутых линуксоидов и установил себе этот самый KDE4. Что тут можно сказать, был сделан большой прогресс в разработке и улучшения интерфейса пользователя. Я перечислять не буду, т.к. их можно посмотреть на официальном сайте. Что еще порадовало, так это то, что увеличилась производительность, по сравнению с третьей веткой. Упростился процесс конфигурации. В общем и целом впечатление весьма приятное.
Теперь вот буду использовать в качестве десктоп окружения по-умолчанию.
Однако, как оказалось чуть позже, возникли некоторые проблемы со звуком:
При запуске какого-нибудь КДЕ-шного приложения, ни одна другая программа не могла воспроизвести звук. При том что до этого все работало замечательно. KDE для вывода звука использует backend Phonon, который в свою очередь использует xine, который в свою очередь использует звуковую подсистему: alsa, oss и т.д.
Для того, чтобы настроить звук, в KDE в system_settings нужно выбрать устройство, через которое будет выводится звук. Однако там присутствовала всего одна звуковая карточка. Оказалось, что для получения списка устройств phonon использует какую-то там функцию из библиотеки alsa, и не отображает устройства без описания. Вылечивается это просто. Добавляем в соответствующую секцию файла /etc/asound.conf строк:
hint {К примеру для микширования через dmix :
show on
description "Name to display for the device"
}
pcm.dsp0 {
type plug
slave.pcm "dmixer"
hint {
show on
description "My dmix sound card"
}}Теперь в настройках KDE выбираем вместо карты по умолчанию, "My dmix sound card",
и у вас есть многопоточный звук.
2/07/2009
Настройка Microsoft-VX 3000 в Linux
После недолгого гугления, обнаружил сайтик, где можно найти кучу драйверов для разных веб камер. Проект называется gspcav1. Моя веб камера тоже в списке поддерживаемых.
Чтобы скомпилировать проект нужно, нужно скачать архив gspca, распаковать и запустить скрипт gspca_build.
В ядре должна быть включена поддержка V4l, и естественно у вас должны быть сорцы вашего работающего ядра.
После компиляции загружаем модуль ядра, modprobe gspca, и вуаля, появляется устройство /dev/video0 - которое собственно и будет вебкамерой.
Все эти действия легко и непринужденно проделываются на ядрах, версии меньше 2.6.27.
В версиях выше 2.6.27 набор драйверов интегрировали в ядро, и перевели на интерфейс v4l2. И после этого вебкамера перестала работать.
На моей системе (Gentoo Linux 2.6.28.1 x86_64) не помогало ничего. Ни одно приложение не хотело отображать картинку с камеры. Вместо этого отображались только помехи.
Сегодня мне все это надоело, и решил я значит скомпилировать старый драйвер gspcav1, от сторонних разработчиков. И у меня это получилось, с помощью лома, и какой то матери.
И так.
В ядре отключаем встроенный драйвер gspca, включаем V4l v1 compatible layer, или как-то так. Пересобираем ядро. Дальше я наваял патчик для gspca, чтобы его можно было скомпилировать с новым ядром. Скачать его можно здесь.
Заходим в каталог gspca, делаем patch -Np0 < ../gspca.patch, затем компилируем и инсталлируем. И О чудо, моя веб камера снова работает. =)
2/03/2009
Материалы конференции Embedded Linux Conference Europe 2008
2/02/2009
Перечислимые типы и строгая типизация.
Перечислимый тип определяется как набор идентификаторов, с точки зрения языка играющих ту же роль, что и обычные именованные константы, но связанные с этим типом.
В языке Си, изначально перечислимый тип отсутствовал, но позднее был добавлен в стандарт ANSI.
Вот пример объявления перечислимого типа в языке Си:
typedef enum my_enum {
A, B, C
} my_enum_t;
Он состоит из трех элементов A,B,C.
Каждый элемент перечисления представляется с помощью типа int.
Фактически эта запись равносильна следующей (на большинстве платформ):
typedef int my_enum_t;
const my_enum_t A = 0;
const my_enum_t B = 1;
const my_enum_t C = 2;
Согласно стандарту ANSI C элементы перечисления по умолчанию нумеруются с 0.
Если какому-либо из элементов присвоить какое нибудь значение, то, все последующие элементы будут увеличиваться на 1, относительно этого значения.
Например:
typedef enum my_enum {
A = 500, B, C
} my_enum_t;
В таком перечислении значение A будет 500, B - 501, C - 502 и т.д.
К чему все это, спросите вы?
Пытаясь портировать одну небольшую и очень известную библиотеку,
на embeddedLinux для Архитектуры ARM9, я наткнулся на следующую проблему:
один и тот же код, скомпилированный компилятором одной и той же версии (gcc-4.1.1), с одними и теми же флагами отказывался работать.
Вот пример того кода, который не работал на ARM9:
1 #include
2
3 typedef enum enum_A {
4 A1 = 0, A2, A3, A4
5 } enum_A_t;
6
7 typedef enum enum_B {
8 B1 = 1000000, B2, B3, B4, B5
9 } enum_B_t;
10
11 int main (int argc, char *argv[])
12 {
13 enum_A_t A;
14 enum_B_t B = B1;
15
16 A = B3;
17
18 printf ("A=%d, B=%d\n", sizeof (enum_A_t), sizeof (enum_B_t));
19 if (A > B)
20 printf ("Hello\n");
21 }
Ошибка состоит в том, что на x86 на консоль выводится слово HELLO, а на arm9 нет.
Как оказалось такую ситуацию можно повторить и на x86 архитектуре.
Где же ошибка:
На мой взгляд строки 16 и 20 - это просто надругательство над всем смыслом перечислимого типа. По моему мнению такое делать нельзя. Но компилятор gcc это прекрасно проглатывает, абсолютно никак не оповещя пользователя о возможных последствиях.
Ведь enum_A_t и enum_B_t это два абсолютно разных типа, с абсолютно разным диапазоном значений.
Такой код работает только потому, что элементы перечисления по сути являются элементами типа int.
Но что будет если gcc начнет оптимизировать?
Как оказалось, для экономии памяти на embedded платформе, в компиляторе была по-умолчанию включена опция -fshort-enums. При включении этой опции компилятор начинает оптимизировать перечисления, для того чтобы они занимали меньше памяти.
Как он это делает?
Просто берет и начинает использовать для хранения элементов перечисления не огромный 4-х байтовый целочисленный тип,а скажем однобайтовый char, или двухбайтовый short. Вот и в нашем случае, компилятор соптимизировал код так, что для хранения элементов типа enum_A_t использовался char, а для хранения элементов типа enum_B_t тип int.
Естественно сравнение в строке 19 всегда будет ложным.
Вывод.
Будьте внимательны при объявлении и использовании перечислений.
Такие ошибки трудноуловимы, и можно просидеть очень много времени в отладчике, пытаясь понять что же все таки не так.