четверг, 5 ноября 2009 г.

Разбор аргументов командной строки в C

Столкнулся с проблемой разбора аргументов командной строки при написании программы на языке С. Вручную делать не захотелось, а, как оказалось, и не требуется - для этого уже есть стандартные POSIX библиотеки. Попробовал getopt - инструмент оказался очень удобным в использовании, так что и сишникам хорошо живётся в этом плане!

Например, чтобы разобрать опцию help, нужно всего лишь следующее:

struct option opt[] = {
{"help", no_argument, 0, 'h'}
};
//...
while((c = getopt_long(argc, argv, "h", opt, &opt_ind)) != -1) {
switch(c) {
case 'h':
fprintf(stderr, "-h [ --help ]\t\t produce help message\n\n");
break;
//...

Хотя это и не единственный путь - здесь небольшой обзор ещё нескольких библиотек.

четверг, 6 августа 2009 г.

Оператор with в Python

Оператор 'with' используется для обвертки блока выполнения методами, определёнными менеджером контекста. Оператор позволяет скрыть общие try...except...finally паттерны для удобного переиспользования.

Интерфейс менеджера контекста в стандартной библиотеке python 2.5 уже реализуют:
- file
- thread.LockType
- threading.Lock
- threading.RLock
- threading.Condition
- threading.Semaphore
- threading.BoundedSemaphore

Список будет расширяться.

Пример использования оператора 'with':


#!/bin/env python
#-*- coding: utf-8 -*-

import threading

class Worker(object):
def __init__(self):
self.lock = threading.RLock()

def execute(self):
with self.lock:
print "thread safe work there"

if __name__ == '__main__':
worker = Worker()
# execute worker.execte() from many threads
# ...
worker.execute()


Примечания:
1. оператор 'with' появился c python 2.5
2. для использования 'with' в python 2.5 необходимо импортировать with_statement фичу из __future__ :

from __future__ import with_statement__
# using 'with'

С python 2.6 'with' работает из коробки :).

Дополнительная информация:
http://docs.python.org/reference/compound_stmts.html#with
http://www.python.org/dev/peps/pep-0343/
http://docs.python.org/reference/datamodel.html#context-managers

среда, 5 августа 2009 г.

Из двух 16-разрядных целых вещественное, 32 разряда.

Раз уж здесь есть советы по типу "sizeof()", то добавлю этот. Наверно интересен для программистов, знающих о C только по наслышке. :)

Задача проста: имеются два 16-ти разрядных целых числа (другими словами, 2 байта информации, которая вроде как число), нужно склеить из них 32-х разрядное, вещественное. Условия задачи, в общем, легко переформулируются, важен принцип решения. :)

Решение просто, как все в C:

int w1 = 62915, w2 = 16456;
ui32 vl = ((w2&0xffff)<<16) | w1&0xffff;
printf("TEST 00: %f\n",*(float*)&vl);

PS: не забывайте про BIG ENDIAN и LITTLE_ENDIAN. ;)

четверг, 25 июня 2009 г.

нечто очевидное

typedef struct some_struct
{
int dummy;
unsigned long long some_field[];
} some_type;

int main() {
int buf;
buf = (int)&((some_type*)0)->some_field[0];
printf("buf = (int)&((some_type*)0)->some_field[0];\n");
printf("sizeof(unsigned long long): %d, sizeof(int): %d, \
sizeof(some_type): %d\n",
sizeof(unsigned long long), sizeof(int),
sizeof(some_type));
printf("buf: %d\n\n", buf);

buf = (int)&((some_type*)0)->some_field[1];
printf("buf = (int)&((some_type*)0)->some_field[1];\n");
printf("sizeof(unsigned long long): %d, sizeof(int): %d, \
sizeof(some_type): %d\n",
sizeof(unsigned long long), sizeof(int),
sizeof(some_type));
printf("buf: %d\n\n", buf);

}


1. (some_type*)0 создали на стеке некий объект и преобразовали его к типу "указатель на структуру some_type". Т.о. по адресу памяти, на который указывает (some_type*)0 будет находится некий мусор, но память будет выделена;

[#########################################################]
[|########################################################]

2. ((some_type*)0)->some_field[1] тут произошло смещение на 1 позицию размером в sizeof(typeof(some_field));

[#########################################################]
[#################################|#######################]

3. &((some_type*)0)->some_field[1] взяли адрес полученной ячейки памяти. Фактически, уже тут мы получаем искомое - объем занимаемой памяти;

4. (int)&((some_type*)0)->some_field[1] компилятор перестал ругаться;

Вуаля, в выражении
(int)&((some_type*)0)->some_field[0]
нам не нужно знать типы структур и полей, чтобы вычислить размер памяти.

понедельник, 22 июня 2009 г.

Использование pthread_create в C++

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

/* pthr_tst.h */
#ifndef PTHR_TST_H
#define PTHR_TST_H

class PTHR_TST;

void *testThr(PTHR_TST * p);

class PTHR_TST {
    public:
       PTHR_TST();
       ~PTHR_TST();
       int createThreads();

    protected:
       friend void *testThr(PTHR_TST * p);

};

#endif

/* pthr_tst.cpp */
#include
#include "pthr_tst.h"

PTHR_TST::PTHR_TST() {}
PTHR_TST::~PTHR_TST() {}

void * testThr(PTHR_TST *p) {
    PTHR_TST * t = p;
    // t->someMethod();
    // someMethod() будет работать в потоке
    delete t;
    return 0;
}

int createThreads() {
    /* тоже хинт. g_tattr используется для задания
    максимального используемого объема памяти потоком */
    pthread_attr_t g_tattr;
    size_t ss=100*1024;
    pthread_attr_setstacksize(&g_tattr, ss);

    pthread_t testthr;
    pthread_create(&testthr, &g_tattr, (void *(*)(void*)) testThr, this);
}

понедельник, 1 июня 2009 г.

О размерности массива [C++]

Бывают случаи, когда необходимо узнать размерность массива. Делается это довольно просто:

int Mas[] = {4, 8, 15, 16, 23, 42};
int Size_Array = sizeof(Mas) / sizeof(int);

В памяти элементы массива располагаются последовательно, а объем памяти выделяемой под массив определяется как произведение всех размерностей массива (общее число элементов) умноженное на длину типа данных массива.

вторник, 26 мая 2009 г.

деликатный switch

Не редко программисты забывают закрывать case ветку оператором break; или любым другим, который бы прекратил исполнение структуры switch. Но так же, достаточно часто программисты намеренно не закрывают case, как, например, в нижеприведенном коде:
// из исходника ls.c
case 'a':
    fts_oprions |= FTS-SEEDOT;
case 'A':
    f_listdot = 1;
    break;

Возникает некоторая двойственность, для человека читающего код может быть не очевидно: ошиблись вы или намеренно оставили case открытым. Для внесения ясности принято во всех случаях когда case необходимо оставить открытым, писать комментарий /* FALLTHROUGH */ . таким образом вышеупомянутый пример приводится к виду:
case 'a':
    fts_oprions |= FTS-SEEDOT;
    /* FALLTHROUGH */
case 'A':
    f_listdot = 1;
    break;

На комментарий так же реагируют некоторые компиляторы и не предупреждают, о, возможно по ошибке, открытом case.

степень двойки


Для возведения числа в степень k = 2^n используется логический оператор побитового смещения "<<". Таким образом, конструкцию вида a << n следует читать как a * k, где k = 2^n.
Аналогичным образом определяется операция деления числа на k = 2^n с использованием логического оператора побитового смещения ">>". Конструкцию a >> n следует читать как a / k, где k = 2^n.
Не стоит забывать о том, что оператор побитового сдвига ">>>" для реализации конструкции деления числа на степень двойки в JAVA не работает с отрицательными числами.

остаток от деления

результатом выполнения кода 65 & 7 будет остаток от деления 65 на 8 = 1. (& - побитовое логическое "И"). В общем случае результат выполнения конструкции a&b равен a%(b+1), где b = 2^n - 1. (% - оператор нахождения остатка от деления левого операнда на правый).
Теоретическая причина по которой конструкция a&b более популярна для нахождения остатка, в том что она исполняется быстрее чем её более понятный для чтения аналог. На практике, последние версии популярных компиляторов в состоянии проводить подобную оптимизацию кода самостоятельно, не говоря уже о том что разница в эффективности исполнения этих двух конструкций вообще не существенна на современных процессорах. В идеале, вы должны знать об этом и других подобных трюках для того чтобы понимать код написанный несколькими годами ранее, но случаи в которых их использование будет оправдано вами в настоящее время действительно встречаются редко.

if statements [ C / C++ ]

Исключительно в целях улучшения читабельности кода рекомендуется вместо структур вида: if ((p = q)) [1] писать: if ((p = q) != NULL) [2]. Это главным образом связано с тем, что программисты часто ошибаются используя '=' вместо '=='.
В случае когда проверка на NULL проводится явным образом[2] у человека читающего код, мысли о том что вы что-то перепутали не возникает, чего нельзя сказать о коде [1].

UPD:
инструкцией if((p = q) != NULL) имеет смысл пользоваться только, если q - это вызов функции, возвращаемое значение которой мы хотим сохранить. Например:
if((r = foo(...)) != 0) err(1, "foo");

thx2 ivaxer
.

обработка ошибок вывода [ C / C++ / Java ]

printf() в случае успеха возвращает число записанных байт.
putchar() возвращает EOF в случае если не получилось записать символ.
С одной стороны хорошо бы каждый раз при вызове любой системной функции проверять возвращаемое значение, но делать это бывает чересчур утомительно, в случае если подобных вызовов достаточно много.
Вместо этого можно проверять были ли ошибки на стандартном потоке вывода перед завершением программы.
В Java для этого пользуются методом checkError(); в С++ для этого пользуются методами fail(), good() или bad(); и в коде на C пользуется функция ferror: if (ferror (stdout )) err (1, "stdout");

сравнение строк [ C / C++ ]

strcmp() возвращает 0 в случае если две строчки равны, что не очень показательно.
Исключительно в целях повышения читабильности кода для проверки на эквивалентность двух строчек принято определять макрос:
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)