Блог О пользователеcpp

Регистрация

С++

Календарь

<< Декабрь 2008  

Пн Вт Ср Чт Пт Сб Вс
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

На странице

  • 7 декабря 2008 | 12:41 Фаст флуд 2. 

    Живя среди других, иногда подвергаешься влиянию всей этой суеты. Случилось даже, что меня одолели мысли о бесполезности С++ в нашем быстром мире и я начал серьезно подумывать на какой язык перескочить. Конечно же, в фаворитах оказался C#. Близкий к С++ синтаксис, поддержка сильной компании и т.д.. И перескочил бы, не повстречайся мне некоторые факты. Факты пока для меня достаточно сырые, и все же я оказался ими впечатлен настолько, что всерьез задумался над тем, куда все это катится и стоит ли катиться вместе со всеми. Факты следующие: чистая операционная система Linux занимает всего несколько мегабайт на жестком диске, а чистая Windows Vista - 15 гигабайт (может мир сошел с ума?). Сам сижу на XP, поэтому пишу с чужих слов, но намерен в скором времени проверить это лично. Отдаю себе отчет в том, что в Vista включена куча прибамбасов и она сразу готова ублажать ленивого пользователя всеми доступными развлечениями. Девственный Linux вряд ли сгодится для подобных тем (если конечно не поставить готовый дистрибутив), поэтому эти факты могут тронуть только сердца ИТ -специалистов, которыми еще не полностью овладели темные силы M$. Предварительные выводы, которые я сделал для себя (пока тоже сырые):

    - Пока жив Linux будет жив C & C++;

    - Пока нужны быстрые и надежные сервера (а когда они будут не нужны?) будет жив Linux.

    - Поставив себе чистый Linux, я получаю возможность конфигурировать его так, как мне необходимо (отличный конструктор, прямо как в детстве!).

    - Когда все собираешь сам, будешь с системой "на ты". Разве это не то, что нужно сисадмину или программисту?

    - Чем больше деталей содержит механизм, тем больше вероятности, что какая-то из них может сломаться. Чем их меньше, тем легче найти поломку. Windows  напоминает Титаник (особенно Vista), где есть все, включая тонны золотых украшений, назначение которых ублажать взоры капризных дам, и помочь быстрее пойти ко дну в случае беды. А сама конструкция такова, что нет возможности при необходимости удалить бирюлички, не сломав что-нибудь полезного. Хотите пересечь на такой штуке океан - ваше право.

    Теги: flood linux windows

  • 7 декабря 2008 | 11:37 Фаст флуд. 

    Фастфуд уже давно стал привычным и даже полюбился большой частью человеческой рассы, причем во всех сферах жизни. Fast life, fast love, fast sex, .., fast death. И в этой спешке просто некогда вдаваться в детали. А если станешь вдаваться - отстанешь от других и все пропустишь (чего именно - не знаю, но знаю, что не успеешь и точка). В этой спешке нужно скорее выпустить продукт, чтобы опередить конкурента, и соответственно, больше заработать. Не сложно заметить, что качество продукта не является приоритетным, опять же касательно всего: от садовода, до крупной софтверной компании. Ремесло больше не цель, не призвание, а средство. И наверно, при таком положении дел несколько глупо ожидать от садовода полезных питательных продуктов, а от софтверной компании - игры захватывающей дух, с завораживающей музыкой, сливающейся с пленяющими сказочными мирами. Зато в порядке вещей купить регулярно "падающий" MS Word от самой крупной компании, которая разрабатывает его на своих же технологиях!

     

    Теги: flood

  • 15 августа 2008 | 14:32 Смена работы 

    Решил сменить работу. Захотелось делать чего-нибудь интересное, да и вообще изменить привычный ритм жизни. Написал резюме, разослал, разместил в банках работы. Больше все откликов получил с hh.ru, но все отклики были ответами на мои отклики — самостоятельно мое резюме никто не нашел.

    По собеседованиям. Прочтение  советов Майерса реально помогло. Чаще всего встречались вопросы касающиеся тем виртуальных функций и наследования, но это не значит, что  другие вопросы остались незатронутыми. Одна фирма осталвила приятное впечатление. Человек, общавшийся со мной на собеседовании показался мне очень компетентным, и, главное, умеющим заинтересовать работой не ради зарплаты.  Касательно С++ вопросов почти не задавал, интересовался способностью мыслить, если я его правильно понял.

    Практических вопросов, вцелом, было немного, и они были несложные. Но даже если мне дают простое задание и пристально наблюдают, как я его обдумываю, мысли у меня концентрируются плохо. Предпочитаю думать, когда никто не мешает. Вот пара подобных вопросов на реализацию:

    1. Реализовать функцию-аналог библиотечной atoi().
    2. Реализовать функцию принимающую массив некоторого типа и переменную этого же типа, содержащую значение, эквиваленты которого нужно выкинуть из массива. Функция должна вернуть размер измененного массива.

    В процессе поиска работы не мог не обратить внимание на вытеснение C++ из некоторых направлений программирования другими языками. Большая часть вакансий по С/С++ относится
    к программированию микроконтролеров, терминального ПО, серверных систем. Тем не менее по другим направлениям С++ пока еще неплохо держит свои позиции.

    Рейтинг языков программирования

    Читал мимоходом некоторые замечения и тесты касающиеся сравнения скорости выполнения управляемого и неуправляемого кода. Управляемый код имеет очевидные удобства и постоянно совершенствуется. Да, это будущее, и оно неизбежно наступает. Но С и С++ не будет погребен, как не был погребен asm — это своеобразный фундамент. Программист, знающий C++ и asm, всегда имеел преимущества перед программистом, знающим только С++. Тоже самое касательно программистов, знающим C++ и C#.
    А пока интересной работы хватает всем. К тому же хорошие С++ кодеры, как я заметил, особо не беспокоятся о своем будущем. Того, кто освоил С++ уже трудно испугать еще чем-либо. К тому же готовится новый стандарт С++. Ну а будущее как всегда неизвестно и непредсказуемо. Любые поптыки сравнивать языки и делать прогнозы рассматриваю как бесполезную трату времени и сил. Вообщем это мои личные наблюдения и мысли.

    P.S.
    новичкам в С++ (кто уже знаком с языком вцелом) рекомендую прочитать С. Майерса, книги 55 и 35 советов. По меньшей мере это интересно, если конечно вам интересен язык С++


    Интервью со Скоттом Майерсом (2003 г.)

    Теги: c cpp job

  • Инициализация структуры.

    Глобальные, а также любые статические переменные простых типов, при создании всегда инициализируются нулями - обнуляются. Все локальные переменные (объявленные внутри функций, кроме статических переменных) должны явно получить начальное значение,
    иначе в них будет содержаться мусор. Если программист забывает проинициализировать локальную переменную, компилятор обычно выдает соответствующее предупреждение. Тоже само происходит и с пользовательскими типами данных (структурами, классами),
    заключенные в структуру переменные обнуляются, если конечно структура не содержит конструктора, вмешивающегося в процесс инициализации. Структуры в стиле Си не содержат конструкторов или функций, но это не значит, что нет способа инициализировать члены структуры данными, отличными от нулей. Допустим объявлена структура и глобальная перменная:
    struct stTest
    {
        bool bl;  // false
        int i;    // 0
        double d; // 0.0
    };

    stTest gT;


    При объявлении переменной gT произошла ее инициализация, т.е. обнуление. Теперь можно каждому полю присвоить нужное значение обычным способом, хотя более оптимально с позиции краткости и экономии процессорного времени заставить компилятор это сделать в момент инициализации. Допустим нужно, чтобы bl = true, i = -1, d = 3.14, выглядит это так:
    stTest gT = {true, -1, 3.14};


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


    Переинициализация структуры.

    Возможна ситуация, когда в процессе использования переменной gT значения ее полей будут изменены, и время от времени им нужно возвращать начальные значения, которые были заданы при первой инициализации. Написать в программе что-то вроде:
    gT = {true, -1, 3.14}; 


    не получится. Есть несколько вариантов, выбирать нужно в зависимости от ситуации.

    1. Если нужно просто обнулить, используют библиотечную функцию:
    memset(0, sizeof(stTest), &gT);


    первый параметр - это значение, каким будет заполнен каждый байт структуры, второй - размер структуры, и третий - указатель на область памяти обнуляемой переменной. Вместо sizeof(stTest) можно было написать sizeof(gT) и получить правильный размер, но лучше так не делать, т.к. все обстоит несколько иначе, если нужно обнулить структуру через
    указатель. Можно зазеваться и передать sizeof() в качестве параметра указатель, забыв его разыменовать. Все скомпилируется гладко, только sizeof() вернет не размер структуры, а размер указателя, а значит обнулятся не все поля.

    Например следующий код содержит описанную ошибку:
    stTest gT = {true, -1, 3.14};
    stTest* p_gT = &gT;
    memset(0, sizeof(p_gT), &gT);


    2. Если полей у структуры немного и сделать это нужно один или два раза, можно просто написать следующий код:
    gT.bl = true;
    gT.i = -1;
    gT.d = 3.14;


    3. Если переинициализацию нужно делать часто или стуктура содержит большое кол-во переменных, можно создать специальную функцию, которая будет получать указатель или ссылку на структуру и выполнять необходимую работу:
    void initStruct(stTest& st)
    {
        st.bl = true;
        st.i = -1;
        st.d = 3.14;
    }

    Затем вызывать эту функцию, передавая в качестве агрумента перменную, которую нужно переинициализировать:
    initStruct(gT);


    4. Создать глобальную константную копию переменной с нужными начальными значениями:
    const stTest initT = {true, -1, 3.14};


    и переинициализировать gT копированием:
    gT = initT;


    Если приложение многопоточное, то лучше сделать холостое использование initT и какого-либо одного потока

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

    struct stTest
    {
        bool bl;  // false
        int i;    // 0
        double d; // 0.0

        static const stTest& init()
        {
            static const stTest obj = {true, -1, 3.14};
            return obj;
        }
    };


    Статическая переменная obj будет создана при первом вызове функции init() и не будет разрушена при выходе из функции. Т.е. все последующие вызовы функции будут уже иметь готовую obj.

    Теперь переинициализация может выглядеть так:
    gT = gT.init();


    или так:
    gT = stTest::init();

    Функция возвращает константную ссылку на переменную, это значит, что предотвращает копирование объекта, а константность не позволить изменить его извне. Т.е. если убрать константность, то станут доступны следующие действия:
    stTest::init() = gT;


    или
    stTest::init().bl = false;


    и т.п., а это нам совсем не к чему.

    В многопоточном приложении также желательно сделать холостой вызов stTest::init() из одного потока.

    Теги: struct c cpp

  • 3 июля 2008 | 08:49 str.append('\0'); 

    void main( )
    {
        std::string str;
        str.append('\0'); // падает
    }

    append() не ругается на получаемый аргумент, зато падает. Поскольку нет перегруженного append() с одним аргументом для одного символа, по всей видимости, вызывается:
    string& append( const element_type *_S ); 

    и '\0' преобразуется к 0 (NULL), ну и в конце концов рушится.

    Теги: std cpp

  • 3 июля 2008 | 06:34 Атавизмы С++ 

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


    struct stXYZ
    {
        int x, y, z;
    };

    stXYZ point;

    хотя следуя синтаксису Си нужно писать:

    struct stXYZ point;

    Сегодня столкнулся с такой задачкой: в чужом классе функция и перечисление имели одинаковое имя. Когда попытался объявить переменную типа перечисления, компилятор не смог понять, что подразумеваю имя типа-перечисления, а не функции. Можно было поменять  одно из имен в классе, и я так бы и сделал, если б не вспомнил про форму записиси языка Си.

    Упрощенный пример:

    enum typeNum {ONE = 1, TWO, THREE};

    void typeNum(const typeNum tn)
    {
        // do anything
    }

    void main( )
    {
        typeNum type_num1;    // так нельзя - неоднозначность
        enum typeNum type_num2; // так можно, явно указывает, что это enum
    }


    Интересно, что в объявлении параметра ф-ии void typeNum(const typeNum tn) неоднозначности не возникло.

    Теги: enum struct c cpp

  • 24 апреля 2008 | 13:26 STL (примеры) 

    Унарный предикат для поиска вхождений подстроки в список строк.


    #include < iostream >
    #include < string >
    #include < list >
    #include < functional >
    #include < algorithm >

    // класс - фуктор для поиска подстроки
    struct str_finder: public std::binary_function< std::string, std::string, bool >
    {
        result_type operator()(const first_argument_type& str_first, const second_argument_type& sub_str)const
        {
            if ( std::string::npos == str_first.find(sub_str) )
                return false;
            return true;
        }
    };

    // фуктор-объект для вывода строк списка
    struct strShow
    {
        void operator() (const std::string& str)const
        {
            std::cout < < "'" < < str < < "'" < < std::endl;
        }
    };

    // функция для вывода строк списка
    void fnShow(const std::string& str)
    {
        std::cout < < "'" < < str < < "'" < < std::endl;
    }


    void main()
    {
        std::list< std::string >    list_str;
        list_str.push_back("one");
        list_str.push_back("two");
        list_str.push_back("three, two, one");
        list_str.push_back("333, five, one");
        list_str.push_back("six");
        // строка-фильтр для удаления
        const std::string str("one");   
       
        // Вывод списка в консоль, используя объект strShow:
        std::cout < < "\nDemo source-list:" < < std::endl;
        std::for_each(list_str.begin(), list_str.end(), strShow());
       
        // Поскольку алгоритм remove_if не удаляет элементы, а всего лишь группирует в начало списка те
        // элементы, которые не должны быть удалены, то после его работы размер списка не меняется.
        // Также алгоримт remove_if возвращает итератор установленный на элемент, следующий за последним
        // из тех, что не должны быть удалены. Конец списка может содержать различный мусор состоящий из
        // копий различных элементов списка, обычно тех, которые были на тех позициях до применения алгоритма remove_if.
        std::list< std::string >::iterator new_end = std::remove_if(list_str.begin(), list_str.end(),
     std::bind2nd(str_finder(), str) );
       
        // Вывод в консоль списка после смещения элементов не подлежащих удалению в начало списка:
        std::cout < < "\nDemo list after moving non-revomed items:" < < std::endl;
        std::for_each(list_str.begin(), list_str.end(), strShow()); 
       
        // Вывод в консоль только конца списка подлежащего удалению:
        std::cout < < "\nDemo end-of-list for deleting:" < < std::endl;
        std::for_each(new_end, list_str.end(), strShow()); 
       
        // удаление конца списка:
        list_str.erase( new_end, list_str.end() );
       
        // снова демонстрация всего списка после всех операций, но теперь используется вдля вывода ф-ия fnShow:
        std::cout < < "\nDemo list after all treatments:" < < std::endl;
        std::for_each(list_str.begin(), list_str.end(), fnShow);

        std::cout < < std::endl;
    }



    Demo source-list:
    'one'
    'two'
    'three, two, one'
    '333, five, one'
    'six'

    Demo list after moving non-revomed items:
    'two'
    'six'
    'three, two, one'
    '333, five, one'
    'six'

    Demo end-of-list for deleting:
    'three, two, one'
    '333, five, one'
    'six'

    Demo list after all treatments:
    'two'
    'six'


    ...
  • Теги: books

  • Описание протокола Socks4


    Определены две операции: Соединиться и сопоставить (CONNECT and BIND).

    1) CONNECT

    Клиент подключается к SOCKS4 серверу и посылает запрос на СОЕДИНЕНИЕ, когда хочет установить подключение к серверу приложений (удаленному серверу). В пакет запроса клиента включается IP адрес и номер порта удаленного хоста (сервера приложений), и пользовательский id, в следующем формате

                        +----+----+----+----+----+----+----+----+----+----+....+----+
                        | VN  | CD |   ПОРТ   | IP уд. хоста    | ID польз.             |NULL|
                        +----+----+----+----+----+----+----+----+----+----+....+----+
    разм полей:       1     1          2              4                  variable                 1

    VN - это версия протокола SOCKS4, должна иметь значение 4.
    CD - код команды для СОКСа, команда CONNECT должна иметь значение 1.
    NULL - это завершающий байт пакета, полностью состоящий из нулевых бит.
    variable - означает не фиксированную, переменную длину

    Сервер SOCKS4 проверяет, разрешен ли такой запрос с заданными IP источника, IP назначения, порта назначения, ID пользователя (userid) и идентификационной информации, которую он может запросить по протоколу IDENT (*) (см. RFC 1413). Если запрос разрешен, SOCKS4 сервер создает соединение с указанным портом удаленного хоста. Ответный пакет посылается клиенту когда соединение с сервером приложений уже установлено, или когда запрос был отклонен, или же когда оперция завершилась ошибкой.
     
               +----+----+----+----+----+----+----+----+
               | VN  | CD | DSTPORT|      DSTIP              |
               +----+----+----+----+----+----+----+----+
    size of:     1     1           2                   4

    VN - это версия протокола, должна иметь значение 0.
    CD - результирующий код, возможны следующие значения:
        90: запрос выполнен
        91: запрос отклонен или завершился ошибкой
        92: запрос отклонен потому, что SOCKS4 сервер не может соединиться с identd (*) клиента
        93: запрос отклонен потому, что клиентская программ и identd (*) сообщают SOCKS4 серверу различные userid
        
    Остальные поля должны игнорироваться.

    Сервер SOCKS4 сразу же рвет соединение после уведомеление клиента об отлоненном запросе или ошибке. Успешный же запрос клиента означает, что SOCKS4 сервер готов передавать трафик в обоих направлениях. С этого момента клиент может обмениваться данными через SOCKS4 сервер, как если бы он был подключен к серверу приложений.


    2) BIND

    Клиент соединяется с SOCKS4 сервером и посылает BIND запрос когда он готовится к входящему соединению от сервера приложений. Это поисходит только после того, как уже было установлено первичное соединение с сервером приложений через SOCKS сервер командой CONNECT. Вот типичный фрагмент последовательности дейтсвий:

    -bind(): получает сокет
    -getsockname(): получает IP адерс и номер порта сокета
    -listen(): готовится принять вызов от сервера приложений
    -использует первичное подключение, чтобы сообщить серверу приложений IP адрес и номер порта, на который ему следует установить соединение
    -accept(): принимает соедининие от сервера приложений

    Назначение операции BIND - это поддержка такой последовательности, когда использование сокета на SOCKS4 сервере предпочтительнее, чем использование сокета клиента.

    Клиент включает в пакет запроса IP адрес сервера приложений, удаленный порт используемый в первичном подключении, и userid.


            +----+----+----+----+----+----+----+----+----+----+....+----+
            | VN  | CD | DSTPORT|      DSTIP              | USERID         |NULL|
            +----+----+----+----+----+----+----+----+----+----+....+----+
    size:      1     1          2                     4                 variable          1

    VN опять равно 4 (версия протокола SOCKS4)
    CD должно быть 2, что означает BIND-запрос

    Сервер SOCKS4 использует информацию от клиента, чтобы решить, принять или отклонить запрос клиента. Сервер отсылает назад к клиенту ответ в таком же формате, как и ответ на CONNECT запрос, т.е.

     
            +----+----+----+----+----+----+----+----+
            | VN  | CD | DSTPORT|      DSTIP              |
            +----+----+----+----+----+----+----+----+
    size:      1     1          2                    4
     

    VN - это версия протокола, должна иметь значение 0.
    CD - результирующий код, возможны следующие значения:
        90: запрос выполнен
        91: запрос отклонен или завершился ошибкой
        92: запрос отклонен потому, что SOCKS4 сервер не может соединиться с identd (*) клиента
        93: запрос отклонен потому, что клиентская программ и identd (*) сообщают SOCKS4 серверу различные userid
        
    Однако, если запрос был принят (CD == 90), тогда поля DSTPORT и DSTIP несут полезную информацию.
    В этом случае, SOCKS4 сервер создает сокет для ожидания входящего соединения и посылает номер порта и IP адрес этого сокета клиенту в DSTPORT и DSTIP соответственно. Если DSTIP в ответе сервера равно 0 (значение константы INADDR_ANY), тогда клиенту следует заменить 0 на IP адрес SOCKS4 сервера, с которым он соединен в данный момент. (Это случается, если SOCKS4 сервер не является мультиадресным хостом)
    Обычно эти два числа могут быть получены приложением клиента с помощью последующего вызова функции getsockname().
    Протокол приложения должен предоставлять способ отправки этих двух значений от клиента к серверу приложений, чтобы он мог начать подключение, когда соединением между ним и SOCKS4 сервером более предпочтительным, чем обычное прямое соединение, которое бывает в нормальных условиях.

    SOCKS4 сервер посылает второй ответный пакет клиенту, когда ожидаемое подключение от сервера приложений установлено.
    SOCKS сервер сверяет IP адрес соединяющегося хоста со значением DSTIP заданного в BIND-запросе клиента.
    Если они не совпадают, тогда во втором ответном пакете клиенту значение поля CD выставляется 91, и SOCKS сервер закрывает оба соединения.
    При совпадении значений, значение поле CD во втором ответе клиенту выставляется 90 и SOCKS сервер спсобен переправлять трафик между этими двумя сторонами соединений. С этого момента клиент может получать/полсылать данные через соединение SOCKS сервера, как если бы он имел прямое соединение с сервером приложений.

    Для обеих операций CONNECT и BIND, сервер устанавливает лимит времени (2 минуты в текущей реализации CSTC) для создания соединения с сервером приложений. Если по истечении лимита времени соединение не установилось, SOCKS сервер прекращает дальнейшие попытки и закрывает свое соедиение с клиентом.

    --------------------------------------------------------------------------------
    (*)
    Кратко о протоколе IDENT:
    Клиент устанавливает соединение с сервером, который, прежде чем слать ответный пакет, устанавливает ответное соединение на порт 113, запрашивает имя пользователя (userid), указывает номера портов с обеих сторон (полагаю, что протокол IDENT нужен из-за отстутствия в протоколе SOCKS 4 каких-либо способов аутентификации клиента).

    Теги: socks4 network