вторник, 23 ноября 2010 г.

Язык C и указатели

Долгое время я путался (да и сейчас путаюсь) в этим порождении C - указатель.
Но, на этих выходных, я нашел очень удобное средство его применения. На самом деле, я думаю этих средств намного больше, но это пока что в первый раз где это мне пригодилось. Правда, и полноценно изучать С я только начал.
Итак, где-же мне это пригодилось ?
У меня есть функция, которая в зависимости от результата возвращает правду или ложь.
Но, кроме того, она перемещается по переданному ей файлу, и прикольно было-бы, если бы она возвращала текст, который читает из этого файла.
Итак, теперь поэтапно, как я к этому пришел.
Начну с малого. Давайте разберемся с указателями.
   int i = 5;
Это еще не указатель. Это целочисленная переменная, расположенная где-то в памяти (в данном конкретном случае - в стеке), и имеющая значение 5.
Для простоты примера, скажем, что она находиться в памяти по адресу 0x0050.
Т.е. в памяти по адресу 0х0050 находится число 5.
Теперь мы хотим передать эту переменную в функцию, к примеру так:
   printf("%d\n", i);
При входе в функцию создается локальная (в области видимости) копия стека, куда повторно заноситься значение переменной i по новому адресу.
Если внутри фунции printf переменная i будет как-то меняться (ну предположим), то на стек основной программы она никак не повлияет, и как бы она внутри функции не менялась - в основной программе переменная i не измениться.
Нужно это как-то проверить. Напишем исходник.
1) Введем переменную, и посмотрим на каком она адресе:
Создаем файлик main.cpp с содержимым:
   #include /* этот заголовок понадобится для функции printf */
   int main(){
   int i=3; /* создаем переменную i и присваиваем ей значение 3 */
   printf("%d\n", i); /* печатаем ее на стандартный вывод ( на экран) */
   printf("%p\n", &i); /* и последнее - распечатаем адрес переменной */
   }

Для компиляции я использовал команду:
   g++ main.cpp
После того, как она отработала, в каталоге с файлом main.cpp у меня появился исполняемый файл a.out. Его и запускаем на выполнение командой:
   ./a.out
Результатом его работы будет 2 строчки:
   3
   0xBFC0AECC

Первая строка - это значение переменной i.
Вторая строка - это ее адрес в памяти.
Попробуем теперь эту переменную передать в функцию, и распечатать ее уже оттуда:

   #include /* этот заголовок понадобиться для функции printf */
   void t(int); /* прототип функции. */

   int main(){
      int i=3; /* создаем переменную i и присваиваем ей значение 3 */
      t(i); /* Вызываем нашу функцию, и передаем в нее переменную */
      printf("%d\n", i); /* печатаем ее на стандартный вывод ( на экран) */
      printf("%p\n", &i); /* и последнее - распечатаем адрес переменной */
   }

   void t(int m){ /* наша функция, в которой мы делаем те-же вещи, */
/* но уже с внутренней переменной */
      printf("m=%d\n", m); /* печатаем значение переменной m */
      printf("&m=%p\n", &m); /* и адрес в памяти внутренней переменной m */
   }

Компилируем еще раз, запускаем, и получаем следующий вывод:
   m=3
   &m=0xBFEB52B0
   i=3
   &i=0xBFEB52CC

Как видим, новая переменная находится совершенно по другому адресу. Давайте попробуем изменить переменную внутри нашей процедуры:
   void t(int m){
      m=4; /* меняем значение переменной с тройки на четверку */
      printf("m=%d\n", m); /* печатаем значение переменной m */
      printf("&m=%p\n", &m); /* и адрес в памяти внутренней переменной m */
   }

Запускаем, смотрим результат:
   m=4
   &m=0xBFF674C0
   i=3
   &i=0xBFF674DC

Т.е. внутри функции мы переменную изменили, но в главной процедуре значение i не поменялось. Как же нам изменить эту переменную изнутри функции ? Вот тут на помощь нам могут прийти указатели.
Мы можем передать в функцию не саму переменную, а адрес в памяти, где она будет находиться. И тогда функция будет работать с этим адресом, а не со своей копией переменной.

   #include
   void t(int*); /* функция теперь принимает указатель на переменную */

   int main(){
      int i=3;
      t(&i); /* и мы передаем указатель на адрес, а не саму переменную*/
      printf("i=%d\n", i);
      printf("&i=%p\n", &i);
   }

   void t(int* m){
      *m=4; /* мы получили адрес, чтобы разименовать указатель, */
/* ставим перед ним звездочку */
      printf("m=%d\n", *m); /* та-же ситуация */
      printf("&m=%p\n", m); /* а вот адрес никак приобразовывать уже не нужно, */
/* в переменной m у нас и так уже адрес переменной */
   }


Компилируем, запускаем и получаем результат:
   m=4
   &m=0xBFFA5B8C
   i=4
   &i=0xBFFA5B8C

Как раз то, что от нас и требовалось. Мы изменили переменную во внутренней функции, и она изменилась в главной процедуре. Здесь главное не запутаться в переменных, а-то очень просто получить access violation доступа к памяти.

понедельник, 25 октября 2010 г.

Установка Qt4

Итак, установка средств разработки:Как любят говрить линуксоиды, она состоит из одной комманды:
apt-get install libqt4-core libqt4-dev libqt4-gui qt4-dev-tools

На самом деле это значит, что нужно зайти в Убунту в Синаптик и установить 4 пакета:
- libqt4-core
- libqt4-dev
- libqt4-gui
- qt4-dev-tools

После этого начнет работать команда qmake.

Вот с нее мы и продолжим в следующей статье.

Свободные рассуждения на планы на будущее


Вот уж пол-года как сижу на Убунте.
Субъективно: не винда, конечно, но пытаюсь привыкнуть.
И столкнулся я с одной проблемой. Под linux есть множество программ. Их можно ставить из репозиториев, подключать разные неофициальные репозитории, качать deb-файлы и ставить из них, можно, в конце концов, собрать из исходников и пользоваться. Но как бы ни было много программ, множество из них дают только частичную функциональность. И сообщество пользователей делиться соответственно на разные группы - кому нужны красивости, а кому нужна функциональность.
И понял я древнейшую истину: хочешь сделать хорошо - сделай это сам.
По-расспрашивал я на форумах и пришел к выводу, что нужен мне для счастья язык Qt, а именно его последняя версия на данный момент Qt4. Буду пробовать пилить его под свои нужды.

И первое, с чего хочу начать - клиент для IRC.

Что ? А, ну да. Устаревший протокол, вам жабер подавай.
Вот только у жабера Вашего потребление трафика дай Боже. А это роскошь на наших корпоративных каналах.

Что-же мне нужно будет от клиента ?
- простота
- поддержка режимов
- поддержка пароля сервисов
- без всякого скриптования
- поддержка всплывающих сообщений

И первое, что нужно сделать - это конечно-же установить средства разработки Qt4.

пятница, 22 октября 2010 г.

Украинизация Epson FX-890

Предистория:
Печатают у нас кассовые документы на матричных принтерах. Для печати используем принтер, указанных в сабже. А он, собака, вместо украинской Э печатает русскую Г, а вместо украинской Ї печатает Э. В общем, все путает.
Принтер достаточно быстрый из матричных, и менять его на LS-300 смысла нету, да и можно ведь полазить по менюшке и выбрать необходимую страницу.
Вот полазили мы, но дело в том, что кодовой страницы CP866 в списке нету. А мы уже успели выбрать какую-то другую. И теперь принтер у нас остался только англо-говоряще-печатающий.
Полезли на просторы Гугл, и нашли ветку espec -> Epson FX-890 Нет кодовой страницы PC866, откуда скачали утилитку APFX8902190_Ver10E.exe (пароль: monitor.espec.ws).
Но вот беда - эта программа никак не хочет подключаться к нашему принтеру. Ни LPT ей не подходит, ни USB. Пробовали и разные порты, и разные компьютеры. В общем пол дня на это убили, пока опять не полезли в гугл.
И тут нас осенило - а не проверить ли на сайте EPSON какую-нить утилитку. Там программа нашлась. Называется она Epson Remote Configuration Manager Utility.
Ну, и теперь перечень действий с нею:

На самом деле все достаточно просто.
1) Устанавливаем эту программу (Epson Remote Configuration Manager Utility).
2) Она создает каталоги с настройками:
c:\Program Files\EPSON\EPSON Remote Configuration Manager\model\
3) В файле FX890.cfg ищем секцию "Character table" и дополняем двумя записями:
Код:
"CP 866 UKR" : code=0010
"CP 866 RUS" : code=0025
4) Стандартными средствами утилиты выбираем нужную кодовую страницу и заливаем на принтер.

Если таких принтеров несколько, то можно вылить настройки в бинарник, и просто распечатать (к примеру из FARа) на матричный принтер. Или скопировать файлик на порт LPT, к которому у Вас подключен этот принтер.