Попробуем теперь использовать получившуюся программу рисования диаграммы наследования с реальным кодом, т.е. взятым из реального мира. Вопрос в том, какой именно код взять? Лучший кандидат для проверки - наша программа рисования, testclang.cpp! Что может быть реальнее? :)
— Потому что ты тут, — просто сказал Кот. — Иначе бы ты сюда не попала.
21 марта 2016 г.
10 февраля 2016 г.
CLang API: рисуем диаграмму наследования (clang-3.7)
Попробуем использовать CLang API для чего-нибудь полезного, например, для рисования диаграммы наследования.
В Clang API уже есть подобный функционал - функция CXXRecordDecl::viewInheritance(). Функция viewInheritance рисует диаграмму наследования для заданного класса используя библиотеку GraphViz. Но делает она это не совсем так, как мне бы хотелось. Поэтому я попробую написать свою собственную процедуру рисования диаграммы наследования, используя программу dot из пакета GraphViz.
3 февраля 2016 г.
CLang API: обход AST (clang-3.7)
Попробуем теперь реализовать обход AST встроенными методами (по мотивам статьи "How to write RecursiveASTVisitor based ASTFrontendActions"). На мой взгляд, реализация этой задачи стала намного проще по сравнению с версией 2.8.
20 января 2016 г.
CLang API: минимальный проект (clang-3.7)
После долгого перерыва я решил вернуться к попыткам использования clang API по нескольким причинам. Во-первых, clang API за это время продвинулся довольно далеко и стал "мощнее", так что хочется попробовать новые версии. Во-вторых, в старых статьях используется более ранние версии clang, а мне регулярно задают вопросы типа "почему у меня не компилируется/линкуется", поэтому хочется и обновить свои знания и добавить статьям актуальности. В-третьих, за пять лет внятных примеров с использованием clang так и не появилось, надо исправить такую несправедливость. Ну и в конце концов меня не оставляет надежда реализовать одну идею со статическим анализом кода, о которой, может быть, напишу позже.
Итак, попробуем написать и собрать минимальный проект для clang API на платформе Linux, используя последнюю стабильную версию llvm и clang. На момент написания статьи это версия 3.7.0.
23 августа 2013 г.
Цитата: Купер
Примечательная статья на Хабре про то, как дети не умеют пользоваться компьютерами, и про то, что это (почему-то) должно нас беспокоить. Это крик души человека, которого достали тупые пользователи, не умеющие настроить браузер для работы через прокси-сервер, а он один тут в белой тунике стоит. Напоминает анекдот про сантехника — "Учись! А то так и будешь всю жизнь ключи подавать."
Всё бы ничего, да только комментарии и количество народа, заплюсовавшего статью, наводят на мысли о том, что автор далеко не одинок, и да! в этом мире полно людей, желающих сделать мир лучше...
Ну что ж, удачи им всем! Главное — не бояться тунику запачкать.
Программисты вовсе не злодеи. Они много работают, чтобы сделать свои программы легкими в использовании. К сожалению, судят они по себе, так что программы получаются легкими в использовании лишь для других разработчиков программного обеспечения, но не для обычных людей.Алан Купер, "Психбольница в руках пациентов"
14 августа 2013 г.
Оптимизация Ubuntu под VirtualBox
How to improve performance of VirtualBox when UNITY_LOW_GFX_MODE is not working?
11 июня 2013 г.
Десять очень полезных возможностей C++11
Хорошая статья на Хабре: Десять возможностей C++11, которые должен использовать каждый C++ разработчик. Название, правда, слегка преувеличенное, хотя менее полезной статья от этого не становится.
В статье обсуждаются такие возможности как:
- auto
- nullptr
- range-based циклы
- override и final
- строго-типизированный enum
- интеллектуальные указатели
- лямбды
- non-member begin() и end()
- static_assert и классы свойств
- семантика перемещения
5 июня 2012 г.
String Similarity
Очень долго долбался с задачей "String Similarity" с сайта InterviewStreet. И так, и эдак ковырял, но удавалось уложиться только в 8 тестов из 10.
А на самом деле оказалось, что нужно просто применить Z-функцию. Мда, пошел читать букварь... Кстати, не могу найти английское название Z-функции. Если кто знает, напишите, плз.
З.Ы. На Хабре можно почитать хороший разбор алгоритмов поиска подстрок.
23 апреля 2012 г.
Цитата: Линдхольм
Взято отсюда. На языке оригинала цитата звучит лучше, чем в переводе, поэтому оставляю как есть.
Most companies (including web startups) are looking to “wow” with their products, when in reality what they should be looking for is an ‘of course’ reaction from their users.Christian Lindholm,
Chief Innovation Officer at Fjord
В двух словах смысл следующий: хорошо спроектированный продукт в первую очередь должен вызывать у пользователя чувство, что он знает, как пользоваться продуктом, а уже потом чувство восхищения формами.
17 апреля 2012 г.
Visual Studio и googletest
В инете довольно много вопросов типа "как перенаправить вывод googletest с консоли в окно VS Output" от людей, которые пытаются подружить Visual Studio и googletest. Советы им дают самые разные, например, использовать PostBuildEvent или установить какой-нибудь плагин к Студии.
Хотя на мой взгляд самый удобный (гибкий, масштабируемый, переносимый) способ - это создать свою реализацию класса Printer и подключить её к фреймворку параллельно с остальными принтерами. Такой подход описан в примере №9 док-ции по GoogleTest Framework.
Сначала реализовать класс принтера, наследованный от EmptyTestEventListener:
// Provides alternative output mode which produces minimal amount of
// information about tests.
class TersePrinter : public EmptyTestEventListener {
void outDebugStringA (const char *format, ...)
{
va_list args;
va_start( args, format );
int len = _vscprintf( format, args ) + 1;
char *str = new char[len * sizeof(char)];
vsprintf(str, format, args );
OutputDebugStringA(str);
delete [] str;
}
// Called after all test activities have ended.
virtual void OnTestProgramEnd(const UnitTest& unit_test) {
outDebugStringA("TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED");
}
// Called before a test starts.
virtual void OnTestStart(const TestInfo& test_info) {
outDebugStringA(
"*** Test %s.%s starting.\n",
test_info.test_case_name(),
test_info.name());
}
// Called after a failed assertion or a SUCCEED() invocation.
virtual void OnTestPartResult(const TestPartResult& test_part_result) {
outDebugStringA(
"%s in %s:%d\n%s\n",
test_part_result.failed() ? "*** Failure" : "Success",
test_part_result.file_name(),
test_part_result.line_number(),
test_part_result.summary());
}
// Called after a test ends.
virtual void OnTestEnd(const TestInfo& test_info) {
outDebugStringA(
"*** Test %s.%s ending.\n",
test_info.test_case_name(),
test_info.name());
}
}; // class TersePrinter
Теперь подключить к юнит тестам вместе с другими принтерами:
UnitTest& unit_test = *UnitTest::GetInstance(); TestEventListeners& listeners = unit_test.listeners(); listeners.Append(new TersePrinter);
Всё. Теперь результаты будут выводиться без проблем и в окно Output, и в консоль, и куда-то еще, если подключены дополнительные принтеры. Формат вывода можно изменять по своему вкусу. Кроме этого, по клику в окне Output можно будет "прыгать" на код "свалившегося" теста.
6 апреля 2012 г.
Задачи на собеседованиях: оптимизация
Часто встречающаяся задача на оптимизацию.
Есть два шарика и небоскрёб в 100 этажей. Если бросать шарики из окон небоскрёба, то начиная с какого-то этажа они будут разбиваться вдребезги (и после этого разбившийся шарик уже нельзя будет использовать). Нужно предложить алгоритм, который поможет найти этот роковой этаж за оптимальное число итераций. Шарики не обязательно сохранять целыми к концу алгоритма.
26 марта 2012 г.
Проблемы переносимости: mutex
О проблемах переносимости приложений с использованием мьютексов. Мьютексы есть и в Windows и в POSIX, только работают они по-разному.
В Windows мьютексы позволяют выполнять рекурсивные локи из одного и того же потока без каких-либо deadlock'ов. В этом случае просто инкрементируется счетчик рекурсивных локов. Соответственно, чтобы освободить мьютекс для других потоков нужно будет столько же раз выполнить unlock(). Это их стандартное поведение, которое никак не изменить. Нужно просто учитывать это при дизайне алгоритмов приложения.
В POSIX мьютексы по-умолчанию не позволяют выполнять рекурсивные локи (т.е. второй вызов лока переведет поток в состояние ожидания), однако такое поведение может быть изменено путем изменения типа мьютекса. Возможно три варианта: 1) рекурсивные локи возможны (PTHREAD_MUTEX_RECURSIVE); 2) рекурсивные локи невозможны (PTHREAD_MUTEX_NORMAL); 3) режим errorcheck - рекурсивные локи невозможны, но вместо ожидания функция lock() возвращает ошибку (PTHREAD_MUTEX_ERRORCHECK).
Получается, что при необходимости портирования приложения с одной платформы на другую возможны некоторые проблемы. Например, при переходе с POSIX на Windows поведение PTHREAD_MUTEX_NORMAL невозможно, если не предусмотрено архитектурой. Как вариант, нужно будет заменить "родной" Windows-мьютекс на искусственный - можно использовать для этого семафор со значением 1, либо использовать какую-то стороннюю реализацию мьютекса, например из библиотеки Boost.
19 марта 2012 г.
Цитата: Фридман
Девочки, когда мне было столько лет, сколько вам, мои родители говорили: "Том, доедай свой завтрак - люди в Китае и Индии умирают с голоду". А сегодня я говорю вам: "Девочки, доделывайте ваше домашнее задание — люди в Китае и Индии умирают от желания получить вашу работу".
В современном Китае Билл Гейтс — это Бритни Спирс. В современной Америке Бритни Спирс — это Бритни Спирс. Вот, в чем наша проблема.
"Плоский мир: краткая история XXI века"
11 марта 2012 г.
Бесплатная альтернатива valgrind под Windows
Бесплатная утилита с функциональностью memcheck — Dr.Memory. Я давно такую искал, наконец-то она появилась.
Работает под Windows и Linux. Запускается из консоли, довольно легко настраивается (например, на отсеивание ненужных срабатываний). Отслеживает утечки памяти, неправильное освобожение, чтение/запись в "неправильные" области и т.п.
При этом позиционируется как самый быстрый, уверяют, что обгоняет даже valgrind. Думаю, что коммерческим инструментам он всё же будет проигрывать, но пользоваться им вполне можно — пробовал сам под Windows, рекомендую.
Вообще хороший список таких альтернатив: http://stackoverflow.com/questions/413477/is-there-a-good-valgrind-substitute-for-windows
6 марта 2012 г.
Шовинизм от Майкрософт
Помню давным-давно в далекой далекой галактике в MS Visual C++ 6 был пункт меню "Generate Makefile", который делал возможным сборку C++-проектов без запуска IDE. Правда, Makefile использовал какие-то свои правила только частично похожие на обычные posixсовые, и вместо make был NMAKE. Но это мелочи.
Недавно обнаружил, что MS на этом не остановилась. Сейчас в VC++ 2010 еще пока есть NMAKE, но пункта генерирования makefile уже нет. Если хочется использовать makefile, то его нужно писать руками. Если есть нужда автоматизировать сборку проектов, то нужно пользоваться утилитой msbuild, которая идет в комплекте .Net Framework.
Отдельная утилита сбоки есть - и на том спасибо, как говорится. Да вот беда - чтобы собрать проект VC++ 7.0 при установленном .Net Framework 4, нужно либо открывать проект в IDE для конвертирования файла проекта в более новый формат, либо устанавливать более старый .Net Framework. Другого способа, кажется, нет.
Учитывая "нововведения" в последних версиях MSVS, то IDE скоро будет нужен только для сборки проекта.
UPD. В дополнение к .Net Framework еще нужно установить Microsoft Windows SDK с выбранными ".NET Development"->"Tools", "Visual C++ compilers" и "Intellisense and Reference Assemblies". Иначе проекты Visual C++ 2010 собираться скорее всего не будут.
26 декабря 2011 г.
Как получить системную строку форматирования времени
Получение системной строки форматирования даты и/или времени:
- В Linux:
char *nl_langinfo(nl_item item);в параметре
itemзадать значенияD_T_FMT,D_FMTилиT_FMT. - В Windows:
int GetLocaleInfo(в параметре
__in LCID Locale,
__in LCTYPE LCType,
__out LPTSTR lpLCData,
__in int cchData);
LCTypeзадать значенияLOCALE_SSHORTDATE,LOCALE_SSHORTDATEилиLOCALE_SSHORTTIME.
20 декабря 2011 г.
Code @ C++: Find sum of elements in the array
21 октября 2011 г.
Как вернуться к интерфейсу Gnome Classic в Ubuntu 11.10
Новый интерфейс Ubuntu мне очень нравится, и он даже работает в режиме интеграции дисплея на VirtualBox. Но всё же на VirtualBox новый интерфейс подтормаживает, поэтому я вынужден вернуться на старый добрый Gnome Classic:
- Установить пакет gnome-session-fallback:
sudo apt-get install gnome-session-fallback - Выйти из текущей сессии (log out)
- На экране ввода пароля нужно в Настройках выбрать тип оболочки Gnome Classic
- Ввести пароль и выполнить вход. Теперь Ubuntu будет использовать Gnome Classic по умолчанию.
Источник: http://www.upubuntu.com/2011/10/how-to-use-gnome-classic-on-ubuntu-1110.html
19 сентября 2011 г.
Выключение компрессии в OpenSSL 0.9.8
В OpenSSL реализована встроенная поддержка zlib и по умолчанию включена компрессия пересылаемых пакетов данных. Причем при сжатии очередного пакета используется информация об уже сжатых и отосланых пакетах. Например, если вы отсылаете три одинаковых пакета по 400 байт, и первый пакет сжимается до 275 байт, то второй и третий пакеты в сжатом виде займут всего по 12 байт. Такой подход очень экономит трафик, но применим только к протоколу TLS, потому что он гарантирует доставку пакетов и сохраняет последовательность, в которой пакеты были отосланы. Понятно, что для протоколов с негарантированной доставкой такой подход к сжатию не может быть применён. Это подтверждает RFC 3749 "TLS Compression Methods", в котором написано следующее:
Some compression methods have the ability to maintain state/history information when compressing and decompressing packet payloads. The compression history allows a higher compression ratio to be achieved on a stream as compared to per-packet compression, but maintaining a history across packets implies that a packet might contain data needed to completely decompress data contained in a different packet. History maintenance thus requires both a reliable link and sequenced packet delivery.
Протокол DTLS, выбранный для нашего проекта, был разработан специально для UDP и не гарантирует доставку пакетов. Но большей частью он основан на TLS, и по идее реализация протокола DTLS должна учитывать требования RFC 3749.
К сожалению, в OpenSSL этот момент не учитывается и в DTLS сжатие используется точно также, как и в TLS. Совершенно очевидно, что при потере одного из пакетов вся передача будет нарушена, и даже если этот пакет придет позже, то восстановить исходную последовательность принимающая сторона уже не сможет. Такой неприятный момент должен решаться простым отключением компрессии при использовании DTLS, однако в OpenSSL 0.9.8 это превращается в проблему, потому что в API просто нет функции отключающей компрессию. Вот цитата из документации на метод SSL_COMP_add_compression_method:
An OpenSSL server will match the identifiers listed by a client against its own compression methods and will unconditionally activate compression when a matching identifier is found. There is no way to restrict the list of compression methods supported on a per connection basis.
Начиная с OpenSSL 1.0.0 добавлена опция SSL_OP_NO_COMPRESSION, которая делает то, что мне нужно, но в версии 0.9.8 ее нет. В поисках решения я порылся в сети, но ничего внятного, кроме вот этого не нашел:
void disable_openssl_compression()
{
STACK_OF(SSL_COMP)* comp_methods = SSL_COMP_get_compression_methods();
sk_SSL_COMP_zero(comp_methods);
}
Этот хак помогает решить проблему с отключением компрессии, но приносит другую — утечку памяти. Пользоваться таким сомнительным методом не нужно.
Между тем, изучив исходный код OpenSSL, я обнаружил, что информация о доступных компрессорах хранится в простом списке, в который можно добавлять свои компрессоры с помощью функции SSL_COMP_add_compression_method. А раз можно добавлять, то значит должен быть способ и удалять элементы списка. Такой функции в OpenSSL API нет, но после изучения исходников функции SSL_COMP_add_compression_method можно написать свою, не пользуясь хаками, а только предоставленным API:
void disable_openssl_compression (void)
{
int n = sk_SSL_COMP_num(SSL_COMP_get_compression_methods());
for (int j = 0; j < n; ++j)
{
SSL_COMP *comp = sk_SSL_COMP_pop(SSL_COMP_get_compression_methods());
OPENSSL_free(comp);
}
}
12 сентября 2011 г.
Этот загадочный SecurityError (Flex 3)
После очередной порции изменений моё Flash-приложение, загруженное на сервер, перестало работать. То есть не совсем перестало, потому что по click-событиям выполнялось то, что нужно, но визуальные элементы вообще перестали хоть как-то отображаться — кнопки не хайлайтились, текст не скроллился, картинки не отображались... Сложилось такое ощущение, что перестали обрабатываться сообщения, отвечающие за отображение компонентов.
Из-за того, что часть приложения продолжала функционировать, я даже не сразу заметил проблему. При этом локально всё замечательно продолжало работать. Я довольно долго тупил, думая, что это проблемы совместимости установленных Flash-плееров в браузерах и в системе. Но через какое-то время понял, что такое различие в поведении локального приложения и приложения на сервере может вызвать SecurityError. Только где? (Тут я в очередной раз порадовался своей привычке делать маленькие, логически законченные коммиты. Локализовывать баг при таком подходе одно удовольствие и всего лишь вопрос времени.)
Причина обнаружилась в установленном smoothBitmapContent="true" для одного из тегов mx:Image. Так как картинка для тега загружалась не с сервера приложения, то контент по определению считался небезопасным. Доступ к битовым данным в этом случае вызовет SecurityError, а smoothBitmapContent="true" как раз требует такого доступа. Это изменение попало в репозиторий совершенно случайно, в результате неудавшихся экспериментов, но оказалось фатальным для приложения.
Для меня остается загадкой, почему SecurityError вызвал именно такое поведение, когда одна половина приложения работает, а другая половина — нет.
