вторник, 14 декабря 2010 г.
Как узнать в iPhone-приложении, существует ли файл
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:somePath];
среда, 24 ноября 2010 г.
Скрипт для автоматического создания архива проекта с датой и временем в имени файла
Разумеется, нужно вместо MyProject и MyProjectFolderFullPath подставить полные или корректные относительные пути к вашей папке с проектом и к архиву (zip-файлу)
Предположим, что архив будет создаваться в текущей папке:
#!/bin/sh
echo "Enter comment: "
read comment
zipFileName="./MyProject$(date +%Y%m%d_%H-%M)"
echo "compress MyProject to zip archive..."
txtFileName="$zipFileName.txt"
echo $comment > $txtFileName
zip -r $zipFileName MyProjectFolderFullPath
Не забудьте сделать скрипт исполняемым файлом. Теперь в консоли достаточно будет ввести имя файла этого скрипта (проще разместить его в домашней папке) и нажать Enter - и архив папки проекта вместе с одноимённым текстовым файлом комментариев будут выглядеть примерно так:
MyProject20101124_14-20.txt
MyProject20101124_14-20.zip
Очень удобно.
четверг, 30 сентября 2010 г.
Прокрутка и масштабирование в UIScrollView
Вам может потребоваться возможность сдвигать контент в сторону от его изначального положения.
Но если размер вложенного в UIScrollView-вид контентного вида (например UIView или его наследника) равен размеру UIScrollView-вида (то есть размеру контейнера для вашего контента) ИЛИ если вы забыли установить у UIScrollView-вида свойство contentSize таким, чтобы размеры контента были явно больше размеров самого UIScrollView-вида, то прокрутка будет невозможна (или возможно, но только после растягивания контента, чтобы он стал больше размера родительского окна, то есть UIScrollView-вида).
Есть 2 способа сделать возможной прокрутку:
1) сделать изначально большим размер контентного окна и не забыть установить таким же размер через свойство contentSize вашего UIScrollView-вида.
2) установить свойство contentInset, которое устанавливает дополнительное пространство слева, справа, сверху и снизу от контентного окна, чтобы дать возможность его прокручивать (если размеры контентного окна совпадают с размерами родительского окна).
Так вот, я проверил лично: 2-й способ лучше именно для тех случаев, если вам не нужно размещать большой контент, а именно такой, который размером совпадает с UIScrollView-видом (даже если вы и будете его потом растягивать пальцами). Этот способ заметно экономит потребляемую девайсом память, а значит уменьшает шансы на недопустимое падение программы без всякого предупреждения и спасения данных.
среда, 15 сентября 2010 г.
Переполнение памяти из-за больших размеров окон (UIView)
После нескольких дней поиска (когда программа перестала падать после закомментирования содержимого функции drawRect класса моего окна, наследующего от UIView) удалось случайно выяснить, что слишком большой размер окна (который можно задать либо в Interface Builder либо через self.bounds.size) требует слишком много памяти (в моём случае - это цена за возможность безтормозной прокрутки такого большого окна, если оно отображает контент для UIScrollView). Размер окна составлял примерно 4000 на 2500 пикселей.
Стоило лишь уменьшить размер окна в половину, как падение программы прекратилось.
Ранее программа не падала при прежнем большом размере окна. Но стоило только добавить поддержку автоматического поворота интерфейса при изменениях ориентации девайса, как эта проблема вылезла наружу. Вероятно система резервирует памяти больше для окон, размер которых перестраивается в зависимости от ориентации интерфейса.
вторник, 14 сентября 2010 г.
Как вывести в отладочную консоль используемую память в iPhone-приложении
Материал взят из
http://stackoverflow.com/questions/2786539/iphone-memory-usuage
#import mach/mach.h
void report_memory(void) {
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(),
TASK_BASIC_INFO,
(task_info_t)&info,
&size);
if( kerr == KERN_SUCCESS ) {
NSLog(@"Memory used: %u", info.resident_size); //in bytes
} else {
NSLog(@"Error: %s", mach_error_string(kerr));
}
}
среда, 8 сентября 2010 г.
Проблемы с UIScrollView и Landscape ориентацией интерфейса
Моя задача: автоматически перестраивать размеры контент-вида (именно того вида, который передвигается внутри UIScrollView) так, чтобы его длина и ширина были больше длины и ширины UIScrollView окошка в целое число раз (константу) при любом положении девайса.
Сейчас (истратив десятки часов на е..лю с горячо любимым Xcode) я прихожу к выводу, что бесполезно пытаться программно перестраивать размеры контент-вида (того самого, который можно передвигать пальцем используя UIScrollView). Приложение всё равно игнорирует (во всяком случае при визуальном тестировании на девайсе) весь ваш код, и продолжает упёрто принимать во внимание только тот размер, который вы задавали контент-виду через Interface Builder.
Оказывается, требуется в настройках (см. Inspector в Interface Builder) главного окна (в котором будет расположено окошко UIScrollView) и в настройках самого UIScrollView окошка поставить галочку Autoresize Subviews.
Кроме того, важно выставить правильные настройки (в виде красных отрезков и стрелочек) в разделе Autosizing (см. Inspector в Interface Builder). Мне удалась моя задача, как только я выставил только красные стрелочки и убрал красные отрезки в настройках контент-вида. То есть программное изменение размеров и оффсета контента я в коде тоже оставил и это вероятно работает теперь в совокупности (не стал это выяснять, чтобы не злоупотреблять рабочим временем - главное теперь работает как надо).
Обидно, что для выяснения подобных тонкостей уходят многие часы. Хотя это - цена за бесценный опыт.
ЧЕРЕЗ НЕСКОЛЬКО ЧАСОВ: Теперь после многочасовой возни с отладчиком и отладочной консолью удалось выяснить основную причину всех моих бед.
При повороте девайса можно перехватывать это событие (поворот девайса) как вариант в функции shouldAutorotateToInterfaceOrientation (подробности через Гугл). Так вот, при перехвате этого события размеры Autoresize-окон ещё не поменялись! Если вы будете вызывать при перехвате этого события какие-то функции (меняющие размеры ваших сущностей, в которых вы что-то рисуете), то нельзя ориентироваться на текущие bounds (размеры) ваших окон, которые ещё не успели красиво повернуться, подстроившись под новое положение девайса!
Есть и другая проблема с Autoresize-окнами. Если при перехвате события (поворота девайса) вы захотите поменять размеры этих окон программно, то после этого Autoresize-окна автоматически перестроятся под новое положение девайса (поменяв свои размеры возможно не так, как вам бы хотелось).
четверг, 2 сентября 2010 г.
CodeFest — конференция разработчиков в Новосибирске 23 сентября
CodeFest — конференция разработчиков, посвященная актуальным вопросам разработки, управления проектами и тестирования. Достойные гуру интернет-технологий съезжаются со всей России, чтобы вдохнуть глоток свежих знаний, встретить старых знакомых и завести новые связи.
воскресенье, 4 июля 2010 г.
Высота стандартных iPhone-контролов по умолчанию
Status Bar: 20px
Navigation Bar: 44px
Tab Bar: 50px
Если не ошибаюсь, аналогичная высота и у iPad-контролов.
Помнить эти значения приходится каждый раз, когда вы запихиваете в UIView всякие UITableView и прочие окошки.
Всё-таки Interface Builder при некоторых своих косяках даёт экономию времени (создавать контролы руками через код иногда бывает крайне необходимо, но это в любом случае приходится дольше делать, чем делать несколько движений мышкой в Interface Builder'e - ну и кроме того, снимается ряд головняков, например таких как контроль над утечками памяти программно создаваемых контролов). Особенно я люблю Interface Builder за возможность быстро создать взаимосвязи между контролами и функциями-обработчиками (где в качестве возвращаемого типа указываем IBAction).
Так вот - в ряде случаев применение Interface Builder'а позволяет значительно упростить задачу создавать в одном Xcode-проекте приложение сразу и для iPhone и для iPad (просто для разных экранов работаете мышкой с одноимёнными xib-файлами - поверьте, получается быстрее, чем вручную писать каждый раз if-else или #ifdef ТАКОЙ_ТО_ТИП_ДЕВАЙСА).
среда, 30 июня 2010 г.
Upgrade Current Target for iPad - проблемы!
Вместо него там стоит пункт Transition - который выполняет именно то, что должен был выполнять пункт Upgrade Current Target for iPad.
Должен отметить, мне нравится, куда располагаются xib-файлы для iPad, автоматически генерируемые из одноимённых файлов для iPhone. Но я после этого создаю отдельные папки Resource-iPhone (куда перемещаю ресурсы, специфичные только для iPhone, в том числе и xib-файлы) и Resource-Common (куда перемещаю общие ресурсы). После этого нельзя забыть удалить из проекта потерянные ресурсы (обозначенные красным цветом в дереве Xcode-проекта) и снова присоединить их к проекту уже из их новых папок. Теперь с ресурсами всё выглядит более логично и организованно.
пятница, 11 июня 2010 г.
Quartz-рисование в отдельном потоке
Из основного потока вы можете нажать какой-либо GUI-контрол (например кнопку или слайдер). Если нужно, то можно через изменение некоторых объектов (или даже простых bool переменных) попросить поток рисования изменить параметры рисунка или что-то в этом роде.
Есть одна очень существенная деталь, которую нужно помнить!
Ну само собой, нужно защищать переменные от одновременного изменения их значений из разных потоков одновременно. Для этого существуют различные средства синхронизации, pthread-мютексы (в C/C++), @synchronized-блоки (в Objective C).
Я хотел предупредить о другом. Сейчас я столкнулся с серьёзной проблемой. Оказывается, когда вы захотите сделать контекст (в который вы рисуете что-либо) текущим с помощью вызова функции UIGraphicsPushContext (и потом вернуть всё как было с помощью функции UIGraphicsPopContext) ТО ВАЖНО ЗНАТЬ, ЧТО ЭТИ 2 ФУНКЦИИ МОЖНО ВЫЗЫВАТЬ ТОЛЬКО ИЗ ОСНОВНОГО ПОТОКА ПРОГРАММЫ!
Мне нужно рисовать в контекст (не контекст экрана, а контекст в памяти) текст. Если я не сделаю этот контекст текущим, то текст в результате не нарисуется. Проблема в том, что я должен рисовать текст в отдельном потоке рисования. Из-за этого я вынужден из этого отдельного потока просить главный поток программы делать вызовы этих 2-х функций (UIGraphicsPushContext и UIGraphicsPopContext) и ждать каждый раз пока главный поток не соизволит это сделать (а главный поток может быть занят в это время чем-то важным, как ему кажется). Это приводит к целому ряду проблем, которых можно было бы избежать, если я бы знал об этом заранее (это бы позволило предпринять некоторые меры при предварительном проектировании, ещё до того, как была написана первая строка кода). У меня сейчас даже случаются дедлоки (взаимные блокировки потоков).
Так что, дорогие мои, будьте осторожны, если захотите что-либо рисовать в отдельном потоке, учитывайте этот момент.
Макрос _T при переносе Win32 проектов на iPhone
Чтобы не перелопачивать код, который вам нужно портировать из Windows в iPhone, можете добавить в общий заголовочный файл (например, в исходники, где определены все макросы и константы) такое макроопределение:
#ifdef __IPHONE_3_1
#ifndef _T
#define _T(a) L##a
#endif
#endif
После этого вам должно стать хорошо и приятно :)
среда, 2 июня 2010 г.
Проблемы с isnan функцией (при портировании кода Win32-приложения для iPhone)
// где-то наверху файла
#ifdef __IPHONE_3_1
#include < cmath > // или #include < math.h >
#endif
// где-то в коде
#ifdef _WIN32
if(_isnan(val))
#elif defined(__IPHONE_3_1)
if (isnan(val))
#endif
//////////////////////////////////
// увы, иногда < cmath > или < math.h > бессильны нам помочь (мистика?),
// и тогда делайте так в одном месте, где-нибудь в общем заголовке:
#ifdef __IPHONE_3_1
#define _isnan(x) \
( sizeof (x) == sizeof(float ) ? __inline_isnanf((float)(x)) \
: sizeof (x) == sizeof(double) ? __inline_isnand((double)(x)) \
: __inline_isnan ((long double)(x)))
#endif //__IPHONE_3_1
Если вы хотите, чтобы #ifdef __IPHONE_3_1 условие точно срабатывало, то один из способов гарантировать это - сделать cpp файл типом objcpp (в свойствах файла, если щёлкнуть по имени файла в дереве Xcode-проекта). С заголовочными файлами обстоит немного посложнее, но если заголовочник уже включен в cpp-файл, с которым вы сделали как я советую, то обычно всё в порядке будет и в заголовочном файле.
понедельник, 31 мая 2010 г.
Прошёл сегодня первый тест по C++ на сайте www.odesk.com
Passing Score: 2.50 Your Score: 2.75 Grade: Pass
Results by Topic
Topic Correct Answers(%)
1. Classes 57%
2. Constructors and Destructors 86%
3. Exceptions and Exception Handling 0%
4. Functions and Virtual Functions 75%
5. Inheritance and Object Oriented Concepts 67%
6. Miscellaneous 0%
7. Operator Overloading 75%
8. Pointers and File Handling 0%
9. Standard Template Library, Directives and Macros 50%
10. Syntax and Language Fundamentals 40%
Congratulations!!
By passing this test, you have joined the elite league of individuals who have demonstrated a high level of proficiency in their chosen area.
среда, 26 мая 2010 г.
Разработка для iPhone на PHP и XML
В сообществе фанатов Apple решили, что iPad нуждается в улучшениях
Материал взят из http://hitech.newsru.com/article/24may2010/ipadvsapplefans
В сообществе фанатов продукции Apple полагают, что весь потенциал планшетного компьютера iPad может быть раскрыт только с обновлением операционной системы iPhone OS, сообщает СОТОВИК.ру.
Многим пользователям, например, не хватает поддержки многозадачности наряду с улучшением управляемости.
Основной же проблемой называют слабость базы iPad-приложений: далеко не все готовы удовольствоваться двукратно масштабируемыми на 9,7-дюймовом экране приложениями для iPhone - ну разве что те, у кого зрение не столь остро.
Кроме того, тмечаются неполадки с Bluetooth: подключить беспроводные наушники и клавиатуру можно, однако такая связь зачастую рвется очень быстро. Есть и проблемы с обнаружением устройств, которые якобы все время невидимы для Bluetooth-сети.
Жесткая привязка к iTunes для загрузки приложений и цифрового контента несколько напрягает, хотя всегда есть альтернативные варианты "джейлбрейка", как называют взлом защиты в устройствах Apple.
Планшетник iPad, очевидно, позиционируется Apple как инструмент для потребления контента, а не его создания. Это нашло отражение в приложениях офисного пакета iWork, в котором возможности по вводу данных и их форматирования оказались изрядно урезаны.
воскресенье, 23 мая 2010 г.
Finger Piano Share: 10 пианистов в одном iPhone
Компания Yamaha совместно с двумя партнерами выпустит приложение для iPhone, которое позволит одновременно 10 пользователям играть на виртуальном пианино. Finger Piano Share, именно так называется этот продукт, разрабатывался под руководством японской компании Densan System. После запуска приложения на экране появятся виртуальные клавиши пианино, а размещенные подсказки будут направлять пользователей в игре на музыкальном инструменте.
Программа может быть подключена к MIDI-клавиатуре Yamaha через Интернет, то есть с помощью iPhone можно удаленно управлять MIDI-синтезатором. Работать с приложением могут одновременно до 10 человек, подчеркнул Ацуко Ито (Atsuko Ito), руководитель центра развития звуковых технологий в Yamaha (Yamaha Center for Advanced Sound Technologies).
Кроме того, Finger Piano Share совместимо с приложением Sekai Camera, разработанным токийской фирмой Tonchidot. Оно определяет местоположение устройства с помощью модуля GPS и предоставляет пользователю информацию, связанную с этой географической точкой во время просмотра через камеру.
пятница, 21 мая 2010 г.
Аналог Sleep (Win32) функции в Mac OS (iPhone OS)
Названия функций я поменял, чтобы уменьшить вероятность конфликта имён.
Спасибо разработчикам QT.
#ifndef QTSLEEP_H
#define QTSLEEP_H
#include <pthread.h>
#include <sys/time.h>
static void qt_thread_sleep(struct timespec *ti)
{
pthread_mutex_t mtx;
pthread_cond_t cnd;
pthread_mutex_init(&mtx, 0);
pthread_cond_init(&cnd, 0);
pthread_mutex_lock(&mtx);
(void) pthread_cond_timedwait(&cnd, &mtx, ti);
pthread_mutex_unlock(&mtx);
pthread_cond_destroy(&cnd);
pthread_mutex_destroy(&mtx);
}
void qt_sleep(unsigned long secs)
{
struct timeval tv;
gettimeofday(&tv, 0);
struct timespec ti;
ti.tv_sec = tv.tv_sec + secs;
ti.tv_nsec = (tv.tv_usec * 1000);
qt_thread_sleep(&ti);
}
void qt_msleep(unsigned long msecs)
{
struct timeval tv;
gettimeofday(&tv, 0);
struct timespec ti;
ti.tv_nsec = (tv.tv_usec + (msecs % 1000) * 1000) * 1000;
ti.tv_sec = tv.tv_sec + (msecs / 1000) + (ti.tv_nsec / 1000000000);
ti.tv_nsec %= 1000000000;
qt_thread_sleep(&ti);
}
void qt_usleep(unsigned long usecs)
{
struct timeval tv;
gettimeofday(&tv, 0);
struct timespec ti;
ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000;
ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000);
ti.tv_nsec %= 1000000000;
qt_thread_sleep(&ti);
}
#endif
четверг, 20 мая 2010 г.
Дешевые издания приближают конец книги
Интервью с издателем и известным специалистом по маркетингу Игорем Манном
Кризис привел к обрушению многих крупных компаний. Как оказалось, наличие средств и даже так называемого «административного ресурса» совсем не гарантирует бизнесу безоблачного будущего. О том, что должен делать отдел маркетинга, чтобы этого не случилось, и почему это ему порой не удается, НГС.БИЗНЕС поговорил с известным специалистом по маркетингу Игорем Манном.
Справка: Игорь Манн — совладелец издательства «Манн, Иванов и Фербер», специализирующегося на бизнес-литературе. Работал руководителем маркетинговых подразделений российских филиалов компаний Konica Corporation, Alcatel-Lucent, Арктел, «МИАН» (ныне Kopernik Group).
Первый вопрос к вам как к издателю. Как долго, по-вашему, проживут привычные бумажные книги?
Думаю, книга умрет тогда, когда школьники перестанут на уроках пользоваться учебниками и тетрадками, а перейдут на ноутбуки, планшетные компьютеры или что-то в этом роде. Но трудно спорить — перспективы этого рынка под угрозой. Даже лицензионная электронная версия книги уже сегодня обойдется дешевле печатной как минимум в 5–7 раз. Устройства для чтения тоже дешевеют. Так что уже скоро покупка «одноразовых» книжек, которые используются, чтобы убить время, потеряет смысл. Но это не значит, что исчезнет книга как таковая — она может перейти в разряд предмета интерьера, дорогой игрушки, как сигара, дорогие часы и т.д. Дорогие издания смогут находить спрос еще довольно долго. Мы к этому готовимся и уже сейчас пытаемся сделать книгу чем-то большим, чем просто источник информации. Это касается и общего дизайна, и каких-то фишек в оформлении.
У издателей, конечно, есть иллюзия, что они могут несколько оттянуть кончину книжного рынка, если будут делать книги максимально дешевыми. Но на самом деле такой подход эту кончину только приближает, потому что все больше и больше покупателей не будут отказываться от приобретения плохо изданных «одноразовых» книг именно потому, что простой текст им будет удобнее загружать на свои «таблетки», «смартфоны» и «ридеры».
Слову «маркетинг» в русском языке уже больше 20 лет…
Если быть точным, то где-то 40. В 1971 году появилась первая книга со словом «маркетинг» на обложке.
Тем более. Однако до сих пор этим словом называют в разных компаниях очень разные вещи. Что же все такие это такое? У вас есть для него четкое определение?
У меня нет. Может быть, 10 лет назад я и смог бы привести вам какую-то умную цитату известного ученого, но сейчас сказать просто, что такое маркетинг, я уже не смогу. Есть универсальное определение, подходящее для большинства российских компаний, — это приобретение и удержание клиентов.
Вообще же маркетинг очень сложная вещь — есть разные подходы к пониманию этой сферы знаний. Это и наука, и поддержка продаж, и философия бизнеса. Вообще же определений уже насчитывается порядка трех тысяч.
Кто лучший маркетолог — сам бизнесмен или нанятый специалист?
Это зависит от того, о чем мы говорим. Если речь идет о тактике, то лучше с этим справляется специально нанятый профессионал, имеющий соответствующее образование. А вот что касается стратегии, то в ней в 99 % случаев лучше всего разбирается именно владелец бизнеса. Можно отдать на сторону (на аутсорсинг, как сейчас модно говорить) многие функции, но стратегический маркетинг должен оставаться в руках хозяина бизнеса.
Есть очень хорошие слова основателя компании Hewlett Packard о том, что маркетинг слишком важная вещь, чтобы поручать его отделу маркетинга.
Полезно ли для дела, если владелец бизнеса публичная фигура, или это просто следствие тщеславия и бизнес тут не причем?
На мой взгляд, это хорошо. Если владелец или топ-менеджер лично активно участвует в продвижении продуктов или услуг своей компании, это дает ей массу преимуществ. Во-первых, это конкурентное преимущество, которое нельзя перебить, просто потратив больше денег на рекламу или продвижение. Потому что в этом случае вы имеете дело с личной харизмой, а ее может победить только более мощная харизма.
Второе, товар, за которым потребитель видит конкретное лицо живого человека, вызывает больше доверия. Недаром такие «лица» периодически пытаются просто придумывать, вводя в ролики несуществующих кондитеров, шеф-поваров, экспертов и т.д.
Если вы знаете первое лицо бизнеса, вы понимаете к кому нужно обращаться, если у вас возникнут с этим бизнесом какие-то проблемы. У Олега Тинькова, например, есть блог, в который вы всегда можете написать о каких-то претензиях к его банку «Тинькофф Кредитные Системы». Это совершенно иной уровень взаимодействия.
Но почему одни предприниматели не слезают со страниц газет, а из других слова не вытянешь?
Это зависит от психотипа конкретного человека. Некоторым просто трудно выступать на публике в принципе. Для того чтобы делать это успешно, нужна харизма. Ее можно или воспитать, или смириться с ее отсутствием и компенсировать это какими-то другими достоинствами. Но если кто-то раздумывает, стоит мне светиться или не стоит, то мой ответ однозначен — стоит. Тем более что есть примеры, когда люди, изначально бывшие непубличными, были вынуждены в какой-то момент выйти на свет и теперь даже получают от этого удовольствие. Но, как в любом деле, тут не стоит перегибать палку.
Ещё одно мнение об уровне квалификации программистов
Информация взята из http://anton.shevchuk.name/project-management/developers-rank/
Junior Developer
- оптимист, всегда недооценивает поставленную задачу
- постоянно ощущает нехватку времени
- стесняется показать свое незнание
- постоянно наступает на грабли
- с трудом доводит проект до финальной точки
- тестер – враг – ибо находит баги
- менеджер – не воспринимается еще всерьез
- пока не ориентируется по ЗП, но если ему предложат на $50 больше в другом месте – может уйти
- рутинную работу считает сложной, но должен справляться
Developer
- пессимист, зачастую недооценивает свои силы и боится промахнуться в оценке
- всегда есть время на перекур и чашечку кофе
- не стесняется спрашивать у коллег по цеху, может даже нагло их эксплуатировать
- наступает только на грабли спрятанные в высокой траве
- скрипя зубами доводит проект до ума
- тестер – просто задолбал, хотя есть понимание, что сам налажал
- менеджер – зачем ему мои отчеты?
- уже знает свою рыночную стоимость, повышение ЗП не требует, но узнает о вакансиях на других фирмах, и иногда намекает о своей осведомленности
- если выполняемые таски и проект покажется не интересным, это негативно скажется на проекте – обычно сопровождается криками проект Г.., заказчик М…, и что Вы вообще понимаете в программировании
Senior Developer
- реалист, опираясь на свой опыт, видит "узкие" места проекта и закладывается на риски, а так же сообщает об этом менеджерам
- успевает и делать проект, и посидеть на "митингах", и еще и подсказывать коллегам
- может помочь ближнему, не стесняется сказать, что он чего-то не знает
- если и наступает на грабли – то тут два варианта:
- "грабли" – легли в риски, и все проходит безболезненно
- "грабли" – наносят критический урон по проекту, ибо Senior допустил ошибки при разработки архитектуры (иль еще где, но не менее фатально)
- удачно завершенный проект – доставляет истинное удовольствие (и психологическое и материальное)
- тестер – советник в плане юзабилити
- менеджер – щит, который тоже не любит неадекватного заказчика
- хорошо знает себе цену, не стесняется требовать повышения ЗП
- прекрасно понимают, что работа может быть рутинной, но это не должно влиять на качество кода, может ворчать, но работу будет делать
Если Вы располагаете достаточным количеством ресурсов, и при этом в наличии как Junior’ы так и Senior’ы – то судьба проекта может сильно зависеть от состава команды, так что будьте внимательны:
- не стоит ставить Junior’а к зубрам программирования, если среди них нет человека способного заняться его обучением: и новичок ничему не научиться, и “зубры” будут в бешенстве
- если проект разрабатывается лишь Junior’ами – держите руку на пульсе такого проекта и купите валерьянку – себе и заказчику ;)
- не стоит садить Senior’а за проект уровня “для чайников” – проект будет сделан и сдан, вот только разработчик от скуки начнет думать о работе в другом месте
Ну и еще немного информации к размышлению:
Ошибки которые совершают разработчики, когда начинают задумываться о повышении ЗП:
- Переоценивают себя – требовать ЗП не соответствующую Вашему уровню – это верный путь остаться без работы
- Устраивать сыр-бор за 10% прибавку к ЗП – зачастую такое повышение можно решить без лишнего шума и криков
- Узнать, что через дорогу платят на 100$ больше, впасть в депрессию на пару недель, и оказаться на улице, ибо повышать ЗП человеку который последнее время ничего не делает никто не будет – это очень распространенная ошибка, никогда не забивайте на работу, будьте профессионалами.
- Считать, что в соседней конторе работа в 100 раз интересней.
среда, 19 мая 2010 г.
Сравнение строк вне зависимости от регистра символов
bool InsensitiveCompareStrings
(const char* left, const char* right)
{
NSString *leftTitle =
[NSString stringWithUTF8String:left];
NSString *rightTitle =
[NSString stringWithUTF8String:right];
return (NSOrderedAscending == [leftTitle
localizedCaseInsensitiveCompare:rightTitle]);
}
Функция хороша тем, что класс NSString в отличие от std::toupper позволяет отсортировать в правильном порядке даже символы русского алфавита (то есть маленькая русская а будет стоять раньше большой Я).
вторник, 18 мая 2010 г.
Загадочные многоточия в ячейках TableView (UITableViewCell)
Оказалось, что в TableView-контроллерном классе нужно обратить внимание на одну важную функцию:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// бла-бла-бла...
if (cell == nil)
cell = [[[MyCustomTableCell alloc]
initWithStyle:UITableViewCellStyleDefault // или другой стиль
reuseIdentifier:nil] // ВОТ ТУТ ПОСТАВЬТЕ nil вместо CellIdentifier (NSString* строки)
autorelease];
// бла-бла-бла...
}
Оказывается, если вы поставите nil вместо строки, вы тем самым ЗАПРЕТИТЕ ПОВТОРНОЕ ИСПОЛЬЗОВАНИЕ ЯЧЕЕК ОДНОГО И ТОГО ЖЕ РАЗМЕРА, что будет вам гарантировать создание каждой индивидуальной ячейки с её индивидуальными размерами. Теперь весь текст будет исправно влезать (если вы конечно не ошиблись с вычислением размеров под текст).
Кстати, вы можете вообще вместо initWithStyle в вашем классе ячейки добавить множество других функций для более удобной инициализации ячейки, например initWithStyleAndMyParameters - никто не запрещает вам кроме важных стандартных параметров в процессе создания ячейки передать ещё несколько нужных вам параметров (например указатель или даже C++ ссылку на текст). В конце концов, вы можете просто переделать initWithStyle функцию под свои нужды.
пятница, 14 мая 2010 г.
Перенос C++ шаблонов из Visual C++ в Xcode-проекты (для GCC-компилятора)
В данном случае речь идёт о членах-данных шаблонных классов. Согласно стандарту языка, в телах членов-функций (методов) шаблонных классов перед именем члена нужно обязательно писать this-> (при этом это требование не является обязательным, если вы пишите C++ код в Visual Studio). GCC компилятор же упорно не замечает такие члены в телах функций шаблонных классов до тех пор, пока вы не напишите this-> (после этого всё успешно компилируется).
среда, 12 мая 2010 г.
Утечки памяти в дополнительных потоках (в связи с Obj-C объектами) в iPhone-приложениях
Но в ряде случаев (особенно при работе с GUI) самый простой или даже единственный способ получить желаемый результат - использовать Objective C классы (особенно классы из Cocoa Touch). Например, когда нужен вывод изображения на весь экран или рисование иконок в ячейках TableView.
Если рисовать что-либо в дополнительном потоке, то нередко происходят утечки памяти, которые не происходят с тем же кодом, который рисует в основном потоке программы.
Оказывается, всё дело в том, что основной поток изначально окружён 2-мя волшебными вызовами функций (см. функцию main):
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // первый волшебный вызов
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release]; // второй волшебный вызов
return retVal;
}
Так вот, каждый дополнительный поток как правило создаётся и поддерживается в непрерывно работающем состоянии в специальной функции, внутри которой происходит бесконечный цикл (ожидающий новых вызовов функций именно этого потока). Выглядит эта функция примерно так:
- (void)mainRoutine {
// Все autorelease-объекты, которые попадают в Autorelease пул
// получат автоматически сообщение release, как
// только они перестанут быть нужны:
NSAutoreleasePool *pool =
[[NSAutoreleasePool alloc] init];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
while (isThreadShouldBeRunning_)
{
[runLoop runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]];
}
[pool release];
}
Сегодня я узнал приятную вещь. Иногда бывает неудобно париться насчёт такой специальной функции. Оказывается, можно окружить этими 2-мя волшебными вызовами любую функцию, если только вы точно знаете, что она всегда будет вызываться в дополнительном потоке (и никогда в основном потоке). После этого утечки памяти прекратятся! Ура!
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // первый волшебный вызов сделайте в самом начале функции
[pool release]; // второй волшебный вызов сделайте в самом конце функции
воскресенье, 9 мая 2010 г.
Как скопировать файл стандартными средствами си++
std::ifstream ifs(sourceFileName, std::ios::in|std::ios::binary);
std::ofstream ofs(fn.c_str(), std::ios::out|std::ios::binary);
ofs << ifs.rdbuf();
Как создать директорию
#include
Используйте функцию
CreateDirectory (char *DirName, SECURITY_ATTRIBUTES Attribs);
В Linux (вероятно, в iPhone OS и Mac OS, так как они Unix-подобные системы)
#include
Используйте функцию
mkdir (const char *path, mode_t mode);
суббота, 8 мая 2010 г.
Как получить в C++ список всех файлов из текущего каталога (в Windows, UNIX, MS-DOS)
Я проверял для Windows - отлично работает :)
Below is a directory lister for Windows, Unix/POSIX and MS-DOS.
#include
#ifdef _WIN32
/* Compiling for Windows */
#include
int main(void)
{
WIN32_FIND_DATA f;
HANDLE h = FindFirstFile("./*", &f);
if(h != INVALID_HANDLE_VALUE)
{
do
{
puts(f.cFileName);
} while(FindNextFile(h, &f));
}
else
{
fprintf(stderr, "Error opening directory\n");
}
return 0;
}
#else
#ifdef __unix__
/* Compiling for UNIX / POSIX */
#include
#include
int main(void)
{
DIR *dir = opendir(".");
if(dir)
{
struct dirent *ent;
while((ent = readdir(dir)) != NULL)
{
puts(ent->d_name);
}
}
else
{
fprintf(stderr, "Error opening directory\n");
}
return 0;
}
#else
#ifdef __TURBOC__
/* Compiling for MS-DOS */
#include
int main(void)
{
struct ffblk ffblk;
if(findfirst("*.*", &ffblk, 0) == 0)
{
do
{
puts(ffblk.ff_name);
} while(findnext(&ffblk) == 0);
}
else
{
fprintf(stderr, "Error opening directory\n");
}
return 0;
}
#else
#error Unsupported Implementation
#endif
#endif
#endif
суббота, 1 мая 2010 г.
Градации служебной карьеры программистов (junior, senior, team leader и другие)
Хмм (Member указанного форума) написал (далее до конца поста цитирую):
Правильный перевод понятий невозможен в связи с отсутствием в англоязычных странах российской инжерной иерархии. Рекомендуется переводить не тупо текст, а смысл в соответствии с местными традициями конкретной англоязычной страны ("английского" языка не существует в природе - бывают американский, британский, австралийский и другие диалекты).
Что касается наиболее часто встречающейся американской терминологии, то берётся слово инженер и дополняется характеристиками.
1. Специализация
- Software
- Air Space,
- Electrical
- Systems
... и так далее.
2. Стаж
- Senior (опытный - минимум 10-15 лет)
- Junior (начинающий - редко используется в резюме, но может в объявлениях)
... и так далее.
3. Роль
- Associate - работает под руководством других
- Lead - руководство малой конкретной командой
- Project - управление проектом
- Staff - руководство группой самых разных людей
- Pricipal - с основной нагрузкой на менеджмент и принятие решений
... и так далее.
4. Прочее.
- Civil - гражданский, общественные проекты.
... и так далее.
Например, собираем конструкции "Senior Staff Systems Engineer", "Lead Software Engineer", "Civil Aviation Engineer" и тому подобное.
пятница, 30 апреля 2010 г.
Стив Джобс рассказал, почему Apple "не пускает" Flash на свои мобильные устройства
Материал взят из http://hitech.newsru.com/article/30apr2010/applewhynoflash
Глава Apple Стив Джобс разместил на официальном сайте компании открытое письмо Thoughts on Flash ("Размышления о Flash"). В нем он, как сообщает Ferra.ru постарался изложить свое видение причин, по которым Apple не разрешает и не разрешит использование технологии Flash на своих мобильных устройствах.Flash, по мнению Джобса, не является открытой технологией. Хотя технология Flash широко распространена, она полностью контролируется Adobe и доступна лишь от этой компании. Таким образом, Flash фактически по любым меркам является закрытой проприетарной разработкой.
Аргумент Adobe о том, что благодаря отсутствию поддержки Flash пользователи iPhone и iPad лишаются полноценного доступа к веб-ресурсам, глава Apple называет устаревшим. Сайты YouTube, CBS, Netflix, Facebook и многие другие поддерживают работу с мобильными устройствами Apple.
Отсутствие стабильности, безопасности и низкая производительность также являются очень важным аргументом.
Стив Джобс напоминает, что его специалисты в течение нескольких лет просили Adobe показать хорошо работающую технологию Flash на любом мобильном устройстве. Однако этого так и не случилось.
Что касается флеш-игр, Стив Джобс указывает, что им есть неплохая альтернатива в виде программ из App Store. Сейчас в этом онлайн-магазине присутствует более 50 000 игр и развлекательных приложений, причем, многие из них бесплатны.
Снижение времени автономной работы мобильных устройств. Стив Джобс подчеркивает, что Flash видеоролики почти на всех сайтах требуют декодер старого поколения, поддержка которого не реализована в современных мобильных чипах. Поэтому проигрывание видео осуществляется исключительно за счет программной составляющей, что приводит к большой трате системных ресурсов и быстрой разрядке аккумуляторов.
Стив Джобс также отмечает, что технология Flash была разработана для ПК и компьютерной мыши, а не для сенсорных экранов, в то время как у Apple имеется фирменный multi-touch интерфейс, не требующий ничего, кроме пальцев.
Поэтому большинство сайтов с применением Flash все равно придется переписывать под устройства с сенсорным экраном. В Apple решили сразу делать это с применением современных технологий - например, HTML5, CSS и JavaScript.
Работа с локальным SVN-репозитарием
Кроме того, SVN-клиент также имеется в Xcode, но лично я предпочитаю работать через Терминал (командную строку).
1. Сначала нужно создать локальный SVN-репозитарий
Допустим, вы хотите создать репозитарий в виде папки SVN_R, которая будет расположена в папке /Volumes/Data/MyRepositories/ (то есть в папке MyRepositories, которая будет лежать в корне диска Data).
Для этого войдите в папку MyRepositories (через Терминал):
cd /Volumes/Data/MyRepositories
После этого создайте репозитарий такой командой (папку SVN_R не создавайте)
svnadmin create SVN_R
Теперь у вас создана папка, содержащая в себе SVN-репозитарий пока без каких-либо сохранённых там проектов.
Кроме того, вы можете создавать внутри репозитария папки под разные проекты с помощью команды (например, для создания папки Project1Repository)
svn mkdir file:///Volumes/Data/SVN_R/Project1Repos
2. Теперь нужно импортировать имеющийся проект в созданный репозитарий
Теперь вы можете импортировать в этот созданный репозитарий тот проект (папку
svn import /AllProjects/MyProject1 file:///Volumes/Data/SVN_R -m 'Импортировал свой проект 1'
3. Теперь нужно выкачать (chekout) из репозитария этот проект в новую рабочую папку (ту самую папку, которой суждено будет находиться под версионным контролем всю свою жизнь)
svn checkout file:///Volumes/Data/SVN_R ~/MyVersionedProjects
Символ ~ (тильда) означает вашу домашнюю папку (обычно имеющее название совпадающее с именем пользователя в Mac OS или Unix/Linux). То есть из репозитария будет выкачан проект именно в папку MyVersionedProjects, но после этого действия проект будет виден как папка MyProject1 внутри папки MyVersionedProjects (очень важно, чтобы вы не создавали сами папку MyProject1 заранее в папке MyVersionedProjects, иначе в ней появятся одни лишь служебные файлы, а не сам проект). Кроме проекта вы увидите некоторые служебные файлы и папки, в названиях которых может содержаться точка и слово svn. Ни в коем случае не удаляйте их, они нужны для обеспечения версионного контроля.
Теперь работайте с проектом только в этой рабочей папке (куда только что выкачали проект из репозитария).
4. Сохранение очередных версий (commit)
Когда вы захотите сохранить очередную версию вашего проекта, то зайдите в Терминале в РАБОЧУЮ папку проекта и закоммитьте проект
cd ~/MyVersionedProjects
svn commit -m 'Очередная версия (исправил косяк с загрузкой файлов, остался ещё косяк в GUI)'
5. Как посмотреть комментарии к прежним версиям
Для этого с помощью команды cd зайдите в терминале в рабочую папку проекта и выполните команду (для случая, если вы хотите посмотреть комментарии от 1 до 3 версии)
svn log -r 1:3
Вот что вы примерно увидите после выполнения этой команды:
----------------------------------------
r1 | Murat | 2010-04-28 13:58:34 +0700 (ср, 28 апр 2010) | 1 line
Create temporary repositary until purchase Teamprise Explorer
----------------------------------------
r2 | Murat | 2010-04-28 21:00:03 +0700 (ср, 28 апр 2010) | 1 line
Добавил ОПИСАНИЕ.txt - буду описывать, что я понял из исходников (которые не мои)
----------------------------------------
r3 | Murat | 2010-04-29 13:18:54 +0700 (чт, 29 апр 2010) | 1 line
Добавил скрипты для автоматизации сборки, копирования заголовков, очистки проектов
----------------------------------------
Таким образом, можно принять решение о том, к какой именно версии вы хотите откатиться.
6. Как откатиться к одной из предыдущих версий
Наиболее удобно восстанавливать одну из предыдущих версий не в рабочую, а в отдельную папку (но это лишь мой опыт, так что решайте сами на этот счёт).
Создайте отдельную папку (например на рабочем столе папку OLD_VERSION_2). Выполните такую команду, если хотите откатиться ко 2-й версии:
svn checkout
После выполнения этой команды кроме списка из всех восстановленных файлов внизу вы увидите сообщение
Checked out revision 2.
Теперь в папке OLD_VERSION_2 находится вся 2-я версия, полученная из репозитария.
7. Сравнение версий файлов
SVN предоставляет возможность просмотра в Терминале (в командной строке) различий между версиями файлов (для этого введите команду svn help и поищите в интернете справку), но я предпочитаю для этого использовать бесплатную программу kdiff3 (домашняя страница этой программы - http://kdiff3.sourceforge.net/). Эта программа позволяет увидеть различия в текстовых исходниках просто из разных папок (выделяя различия в тексте цветом).
Но SVN позволяет увидеть различия между указанными версиями указанных файлов.
Для того, чтобы увидеть чем отличается 3-я версия файла ОПИСАНИЕ.txt от 2-й версии в текущей папке, введите команду
svn diff -r 2:3 ОПИСАНИЕ.txt
8. Получение справки не отходя от кассы
Общая справка
svn help
Справка по выбранной команде (например, по команде diff)
svn help diff
Как в Mac OS снять блокировку/защиту из всех файлов выбранной папки
Для этого можете запустить Terminal (командную строку), зайти в папку проекта (используя команду cd).
После этого вводите команды:
chflags -R nouchg *
chflags -R nouchg */*
chflags -R nouchg */*/*
chflags -R nouchg */*/*/*
chflags -R nouchg */*/*/*/*
и так далее
Делайте так до тех пор, пока Terminal вам не сообщит, что таких файлов или папок больше не обнаружено (то есть когда глубина вложенных директорий достигнет самых последних закоулков). Это будет похоже вот на что:
chflags: */*/*/*/*/*/*/*/*: No such file or directory
ЕСЛИ КТО-ТО ЗНАЕТ, КАК МОЖНО ЗАМЕНИТЬ ЭТО ПРОСТЫМ SHELL-СКРИПТОМ, ПОЖАЛУЙСТА ПОДЕЛИТЕСЬ ОПЫТОМ.
Как получить пути к наиболее часто используемым папкам в iPhone-приложении
// 1. Путь к папке Documents:
NSString *nsDocsDir =
[NSHomeDirectory() stringByAppendingPathComponent:
@"Documents"];
// 2. Путь к кэш-папке (там хорошо что-либо временное сохранять, такое, что не жалко будет пользователю потерять):
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
NSUserDomainMask, YES);
NSString *nsCachesDir = [paths objectAtIndex:0];
// 3. Путь к папке ресурсов:
NSString* resourcesDir = [[NSBundle mainBundle] resourcePath];
// И ещё пара полезных функций:
NSString* homeDir = NSHomeDirectory(); // вероятно, это корневая папка приложения
NSString* tempDir = NSTemporaryDirectory(); // возвращает полный путь к папке для временных файлов
Внимание: автор не претендует на полноту изложения! Смотрите документацию от Apple.
Как автоматически копировать нужные заголовки в нужное место при сборке Xcode-проекта
Предыстория:
Мне не хочется, чтобы разные проекты зависели от их относительного расположения на диске. При этом я хочу, чтобы заголовки всех моих библиотек (как и сами бинарники) всегда лежали в одном и том же месте, независимо от того, где находятся сами проекты библиотек.
Что я хочу автоматизировать:
В моей ситуации нужно копировать только некоторые заголовочные файлы в определённое место (например, в папку /MyLibs/include/QuartzDrawingLib/).
Раньше я делал это вручную (рискуя однажды забыть скопировать обновлённые заголовки, что порождает множество непредсказуемых проблем из-за несоответствия библиотеке устаревшим заголовкам).
Как это можно сделать?
1-й способ (через добавление скрипта):
Посмотрите на дерево Xcode-проекта. Там есть ниже всех исходников Targets (с иконкой, напоминающей красную мишень). Выберите в Targets вашу цель (как правило с названием вашего проекта), нажмите на неё правой кнопкой мыши и выберите из контестного меню Add - > New Build Phase - > New Run Script Build Phase.
После этого появится окно, в которое нужно ввести текст скрипта. Туда вообще можно вводить любые команды, которые вы могли бы вручную набрать в консоли.
Я ввёл примерно следующее:
destDir=/MyLibs/include/QuartzDrawingLib/
if [ -d "$destDir" ]
then
echo "Directory "$destDir" is found"
else
echo "Directory "$destDir" will be created"
mkdir "$destDir"
if [ -d "$destDir" ]
then
echo "Directory "$destDir" is created"
else
echo "Directory "$destDir" is not created!"
echo "Exit script..."
exit 1
fi
fi
echo Copying headers...
cp Classes/SomeClass1.h $destDir
cp Classes/SomeClass2.h $destDir
cp Classes/SomeClass3.h $destDir
cp Classes/SomeClass4.h $destDir
cp Classes/SomeClass5.h $destDir
и так далее (из папки Classes в текущей директории копируются все ТОЛЬКО НУЖНЫЕ МНЕ заголовки в корень системного диска в папку /MyLibs/include/QuartzDrawingLib/
Теперь не нужно это делать каждый раз вручную.
Всё тоже самое можно сделать ВНЕ ПРОЕКТА как отдельный исполняемый скрипт (в виде обычного текстового файла), только перед написанием всех команд не забудьте сверху написать #!/bin/bash
Кроме того, после написания скрипта (т.е. текстового файла ВНЕ ПРОЕКТА) нужно данный текстовый файл сделать исполняемым - для этого выполните в консоли команду:
chmod +x NameOfScriptFile
2-й способ (который значительно проще, но менее надёжный, так как не гарантирует обновление имеющихся копий заголовков, т.е. их приходится удалять и снова нажимать кнопку Build):
Выберите в Targets вашу цель (как правило с названием вашего проекта), нажмите на неё правой кнопкой мыши и выберите из контестного меню Add - > New Build Phase - > New Copy Files Build Phase (после появления новой иконки добавленной фазы, в настройках этой фазы можно указать абсолютный путь куда копировать те файлы, которые вы будете добавлять в эту фазу в дереве проекта).
Hе забывайте, что с помощью скриптов вы можете автоматически выполнять множество других действий, а не только копировать заголовочные файлы.
Чем заменить функцию stricmp в iPhone-проекте
Смотрите документацию (введите man strcasecmp в командной строке - возможны какие-то различия в возвращаемых int-значениях).
Легендарный редактор vi
vi
Материал из Википедии — свободной энциклопедии
vi (visual) — серия текстовых редакторов операционных систем семейства UNIX.
Содержание |
История
Первая версия была написана Биллом Джоем (англ.) в 1976 году.
В то время наиболее распространённым был редактор ed. Поскольку он был довольно сложным для «простого смертного», George Coulouris разработал редактор em (editor for mortals — редактор для смертных). Билл Джой модифицировал редактор em и назвал его en, а позднее — он получил название ex, на котором и основан vi[1].
Интерфейс
В отличие от многих привычных редакторов, vi имеет модальный интерфейс. Это означает, что одни и те же клавиши в разных режимах работы выполняют разные действия. В редакторе vi есть два основных режима: командный режим и режим вставки. По умолчанию, работа начинается в командном режиме.
В режиме вставки клавиатура используется для набора текста. Для выхода в командный режим используется клавиша Esc или комбинация Ctrl + c .
В командном режиме алфавитные клавиши соответствуют командам перемещения и изменения текста. Так, команды h, j, k, l перемещают курсор на одну позицию влево, вниз, вверх, вправо соответственно, команда x удаляет один символ и т. д. Это позволяет работать без необходимости использования дополнительной клавиатуры и клавиш-модификаторов, таких, как Ctrl , Alt и т. д. Более сложные операции редактирования получаются комбинацией простых, например, 2dw удаляет два слова. Для полнотекстовых операций имеется возможность задавать команды ex в подобии командной строки, например, :1,.s/wiki/[[wiki]]/g заключит все вхождения последовательности символов wiki от начала текста до текущей позиции в двойные квадратные скобки.
Часто используемые команды
- /str — Поиск строки str вперед. str может быть регулярным выражением
- ?/str — Поиск строки str назад
- n — Повторить поиск в том же направлении
- N — Повторить поиск в обратном направлении
- :[range]s/old/new/[g] — Заменить old на new в указанном диапазоне строк range. new и old могут быть регулярными выражениями, а range задается аналогично диапазону строк в редакторе ed. Суффикс g означает заменить во всем файле.
- :e! — перезагрузить текущий файл
- :33 — перепрыгнуть на 33ю строку текстового файла
- i — перейти в режим редактирования
- a — перейти в режим редактирования после текущего символа
- u — отменить последнее действие
- x — удалить символ под курсором
- dd — удалить всю строку
- /qso — найти слово qso в тексте после курсора
- :w — сохранить файл на диске
- :wq — выход с сохранением файла
- :q — выход
- :q! — выход без сохранения файла
Чтобы получить подробную помощь по редактору vi, выполните команду man vi в Unix shell (q — выход из справки).
Использование регулярных выражений
- /^$/ — пустая строка, т.е. только конец строки
- /./ — непустая строка, по крайней мере один символ
- /^/ — все строки
- /thing/ — thing где-либо в строке
- /^thing/ — thing в начале строки
- /thing$/ — thing в конце строки
- /^thing$/ — строка, состоящая лишь из thing
- /thing.$/ — thing плюс любой символ в конце строки
- /\/thing\// — /thing/ где-либо в строке
- /[tT]hing/ — thing или Thing где-либо в строке
- /thing[0-9]/ — thing, за которой идет одна цифра
- /thing[^0-9]/ — thing, за которой идет не цифра
- /thing1.*thing2/ — thing1, затем любая строка, затем thing2
- /^thing1.*thing2$/ — thing1 в начале и thing2 в конце
Чтобы манипулировать не только целыми фрагментами, выбираемыми регулярными выражениями, но и их частями, используются помеченные регулярные выражения: если конструкция \(...\) появляется в регулярном выражении, то часть соответствующего ей фрагмента доступна как \1. Допускается использование до девяти помеченных выражений, на которые ссылаются \1, \2 и т.д.
Вот ряд примеров использования помеченных регулярных выражений:
- s/\(...\)\(.*\)/\2\1/ — Поместить 3 первых символа в конец строки
- /\(..*\)\1/ — Найти строки, содержащие повторяющиеся смежные цепочки символов
- s/^\(..*\)\.\(..*\)/\1.\\2/ — Перенести остаток строки после первой точки на следующую строку
Другие редакторы
Спор между сторонниками vi и emacs является классическим примером «религиозных войн».
На данный момент имеются реализации vi для различных операционных систем. Существуют клоны редактора vi с расширенной функциональностью.
Клоны vi
Ссылки
- Знакомство с vi — метод шпаргалки (англ.) перевод на русский Даниэль Роббинс, президент/исполнительный директор, Gentoo Technologies, Inc.
- Очень кратко о редакторе «VI»
Как выяснить причину EXC_BAD_ACCESS в Xcode
НАЧАЛО ЦИТАТЫ.
EXC_BAD_ACCESS. Debugging this one is on par with figuring out why the wife says “not tonight, honey.” And they are equally unfortunate situations.
Let’s see what we can do about EXC_BAD_ACCESS.
EXC_BAD_ACCESS happens when a message is sent to an object that has already been released. By the time the error is caught, the call stack is usually gone especially if dealing with multiple threads.
How nice would it be to keep a dummy around after the object is released that could stop execution, tell us what message was sent and show us the call stack… well, there’s a way to do just that.
If you set the NSZombieEnabled environment variable, the Objective C runtime will leave a dummy object behind for every deallocated object. When the zombie object is called, execution stops and you can see the message that was sent to the object and the call stack that tells you where the message came from (it doesn’t tell you where you over released the object, but knowing where the object is called from should get you pretty close to the problem.)
To set this variable, go to the info panel of the executable in xcode, and create a new environment variable in the arguments tab by clicking the plus sign in the lower left corner of the window. Name the variable NSZombieEnabled, type YES for the value and make sure that the checkbox is selected.
set NSZombieEnabled variable
set NSZombieEnabled variable
Go ahead and run your program now (in debug mode, because you need the stack information.) When the over released object is accessed, you get an error message similar to this (xcode debug view):
2009-03-30 02:30:36.172 ninjaJumper[3997:20b] *** -[GameLayer retain]: message sent
to deallocated instance 0x59bf670
This shows the class of the object (GameLayer) and the message sent (retain).
Let’s take a look at the stack now:
call stack
call stack
The methods printed in bold are in your code, the others are in some other API. Here you can see that the object was accessed from [Director touchesBegan:withEvent], where an array was copied (most likely the over released object was in the array.)
This information should get you pretty close to the problem.
Once the problem is fixed, make sure that the NSZombieEnabled variable is disabled. You don’t need to delete it, but make sure that the checkbox is unchecked:
NSZombie disabled
NSZombie disabled
Now about the wife. Good luck there. Try a box of chocolate or load the dishwasher for a couple days.
КОНЕЦ ЦИТАТЫ.
К СОЖАЛЕНИЮ, ДАННЫЙ СОВЕТ ПОЗВОЛЯЕТ ОТСЛЕЖИВАТЬ ИМЕНА Objective C КЛАССОВ. Я ТОЛЬКО ЧТО СДЕЛАЛ ТЕСТОВОЕ ПРИЛОЖЕНИЕ, В КОТОРОМ ПОЛЕЗНЫЕ ОТЛАДОЧНЫЕ СООБЩЕНИЯ ВЫВОДЯТСЯ В КОНСОЛЬ ТОЛЬКО КАСАЕМО Objective C КЛАССОВ:
TestClass *testObj = [[TestClass alloc] init];
[testObj release]; // уничтожили объект перед попыткой использования
[testObj printMsg];
В этом случае в консоль будет выводиться информация
2010-04-28 13:02:08.030 ZombieTest[1353:207] *** -[TestClass printMsg]: message sent to deallocated instance 0x3924880)
В случае же с C++ классом:
TestCppClass *tcpp = new TestCppClass();
delete tcpp;
tcpp = 0;
tcpp- >PrintMsg(); // удивительно, но это работает (на экран выводится тестовое сообщение, так как вероятно функция-член класса способна работать и без создания объекта - ЭТО ЧТО, ОЧЕРЕДНОЙ БАГ Xcode?)
delete tcpp; // тем не менее здесь код спотыкается, так как пытаемся уничтожить объект повторно
в консоль выводится то же самое что и без применения совета из приведённой статьи):
2010-04-28 13:04:45.242 ZombieTest[1476:207] TestClass --- printMsg
ZombieTest(1476,0xa0a7b4e0) malloc: *** error for object 0x3917160: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Что делать, если в Xcode-отладчике невозможно переключиться на другой поток
Нашёл некоторое объяснение на http://www.cocoabuilder.com/archive/xcode/248374-debug-problem-in-multithreaded-environment-in-xcode.html
Там такой ответ и совет, надеюсь, программисты умеют читать по-английски:
Sometimes this happens because of the same reason that the backtrace
stack gets bumped off the top of the screen. This is a known problem
that we are investigating. Try toggling the debugger layout (using
the Toggle Debugger Layout command) or deleting the .mode1 file
in your Project's bundle.
вторник, 27 апреля 2010 г.
Как изменить размер стека потока средствами pthread-функций
pthread_t tid_;
// initialize the thread attribute
assert(!pthread_attr_init(&threadAttr));
// Set the stack size of the thread (for example 2 Mb)
assert(!pthread_attr_setstacksize(&threadAttr, 1024*1024*2));
size_t stackSize;
// Проверим, точно ли у нас размер стека 2 Mb
assert(!pthread_attr_getstacksize(&threadAttr, &stackSize));
printf("The stack size is %d. ***\n", (int) stackSize);
// Создаём поток с заданным размером стека
assert(!pthread_create(&tid_, &threadAttr, thread_func, function_));
// подчистим за собой
assert(!pthread_attr_destroy(&threadAttr));
Интересные материалы для C++ программистов в блоге "Алёна C++"
http://alenacpp.blogspot.com/
Например, я только что нашёл интересный пример о константных ссылках (в свою очередь Алёна нашла этот пример в блоге знаменитого Герба Саттера http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry):
ЦИТИРУЮ ИЗ БЛОГА АЛЁНЫ (http://alenacpp.blogspot.com/2008/01/const.html):
Возможно, самый важный const
Герб Саттер у себя в блоге рассказывает про интересный случай с использованием const.
Краткий пересказ для ленивых.
string f() { return "abc"; }
void g() {
const string& s = f();
cout < < s < < endl; // можно ли использовать временный объект?
}
Код несколько напрягает. Создается ссылка на временный объект. Но тем не менее, с кодом все в порядке. Почему так? Потому что в С++ явно специфицировано, что если привязать временный объект к ссылке на const в стеке, то жизнь временного объекта будет продлена. Теперь он будет жить столько, сколько живет константная ссылка на него. В приведенном примере все валидно, время жизни s заканчивается с закрывающей фигурной скобкой.
Это все относится только к объектам в стеке. На члены класса это не действует.
С++ это специфицирует, а как оно в реальности, работает? Герб проверил в нескольких компиляторах, нормально, практически во всех работает.
Легким движением руки убираем const...
И получаем невалидный код, наличие const'а тут важно. Правильный компилятор выдаст ошибку на этапе компиляции.
string f() { return "abc"; }
void g() {
string& s = f(); // все еще нормально?
cout < < s < < endl;
}
И есть еще момент с вызовом деструктора.
Derived factory(); // construct a Derived objectСсылки по теме:
void g() {
const Base& b = factory(); // здесь вызов Derived::Derived
// … используем b …
} // здесь вызывается Derived::~Derived напрямую
//-- а не Base::~Base + virtual dispatch!
Использование const. Часть 1.
Использование const. Часть 2.
КОНЕЦ ЦИТАТЫ
Принципы Agile Software Development
Принципы дизайна ПО представляют набор правил, который помогает избежать плохого дизайна. Принципы дизайна объединены Робертом Мартином, кто собрал их в "Agile Software Development: Principles, Patterns, and Practices" (т.е. "Быстрая разработка ПО: Принципы, Паттерны и Практика"). Согласно Роберту Мартину есть 3 важные характеристики плохого дизайна, которые нужно избегать:
Жёсткость - это когда трудно что-либо изменять в коде, так как каждое изменение оказывает воздействие на слишком много других частей системы.
Хрупкость - когда вы делаете изменение, и это приводит к неожиданной поломке других частей системы.
Непереносимость - код трудно повторно использовать в другом приложении, потому что этот код невозможно освободить от имеющегося приложения.
Принцип Открытости-Закрытости (Open Close Principle или OCP)
Программные сущности такие как классы, модули и функции должны быть открыты для расширения, но закрыты для изменений.
OPC является основополагающим принципом. Вы можете обсуждать его, когда пишете ваши классы, чтобы быть уверенными в том, что когда вам будет нужно расширить поведение, вы не должны будете изменять класс, но можете расширять его. Подобный же принцип применим для модулей, пакетов и библиотек. Если у вас есть библиотека, состоящая из множества классов, то есть много причин для того, чтобы вы предпочитали расширение вместо изменения кода, который уже написан (ради обратной совместимости, возвращение к предыдущему тестированию и т.п.). Это причина, по которой мы должны быть уверены, что наши модули следуют Принципу Открытости-Закрытости. По отношению к классам Принцип Открытости-Закрытости может быть гарантированно полезен засчёт использования Абстрактных Классов и конкретных классов для реализации их поведения. Это будет вынуждать иметь Конкретные Классы в качестве расширяющих Абстрактные Классы вместо их изменения. Некоторые частные случаи этого принципа есть Шаблонный Паттерн и Стратегический Паттерн (Template Pattern and Strategy Pattern).
Принцип Инверсии Зависимостей (Dependency Inversion Principle)
Высокоуровеневые модули должны не зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Принцип Инверсии Зависимостей (Dependency Inversion Principle) формулирует, что мы должны отделять высокоуровневые модули от низкоуровневых модулей, вставляя слой абстракции между высокоуровневыми классами и низкоуровневыми классами. Более того этот принцип инвертирует зависимости: вместо написания наших абстракций, основанных на деталях мы должны писать детали, основанные на абстракциях.
Инверсия Зависимостей или Инверсия Контроля являются более понимаемыми терминами если ссылаться на способ, которым эти зависимости реализованы. Классическим способом в ситуации, когда программный модуль (класс, фреймворк, ...) нуждается в каком-нибудь другом модуле, он инициализует и держит прямую ссылку на этот другой модуль. Это приводит к тому, что 2 модуля становятся туго спаренными. Для их разъединения первый модуль будет обеспечиваться хуком, т.е. крючком (свойство, параметр, ...) и внешний модуль контролирующий зависимости будет добавлять ссылку на второй модуль. Засчёт применения Инверсии Зависимостей модули могут быть легко изменяемы другими модулями всего лишь засчёт изменения модуля зависимостей. Фабрики и Абстрактные Фабрики могут быть использованы в качестве фреймворков зависимостей, однако они являются специализированными фрейморками для того, что известно под названием Инверсия Контрольного Контейнера (Inversion of Control Container).
Принцип Отделения Интерфейса (Interface Segregation Principle)
Клиенты не должны принуждаться к зависимости от интерфейсов, которые они не используют.
Этот принцип учит нас заботиться о том, как мы пишем наши интерфейсы. Когда мы пишем интерфейсы, мы должны позаботиться о добавлении только тех методов, которые там должны быть. Если мы добавляем методы, которые не должны быть там, тогда классы реализующие интерфейс будут должны реализовывать эти лишние методы так же как и остальные методы. Например, если мы создаём интрфейс, называемый Worker (Рабочий) и добавляем метод lunch break (обеденный перерыв), тогда все workers (рабочие) будут должны иметь реализацию этого лишнего метода. А что если рабочий оказался роботом?
В качестве умозаключения приходим к тому, что Интерфейсы содержащие методы, которые не специфичны для них, такие методы приводят к тому, что интерфейсы называют загрязнёнными или жирными. Мы должны избегать создания таких интерфейсов.
Принцип Единственной Ответственности (Single Responsibility Principle)
Класс должен иметь только одну причину для изменения.
В этом контексте ответственность рассматривается как единственная причина для изменения. Этот принцип утверждает, что если мы имеем 2 причины для изменения класса, то мы должны разделить функциональность на 2 класса. Каждый класс должен иметь только одну ответственность, и в будущем, если нам будет нужно сделать одно изменение мы собираемся делать это в классе, который которые удерживает эту одну ответственность. Когда нам нужно делать изменения в классе, который имеет больше ответственностей, изменение может оказать воздействие на другую функциональность классов.
Принцип Единственной Ответственности был введён Tom DeMarco в его книге "Structured Analysis and Systems Specification, 1979". Роберт Мартин реинтерпретировал эту концепцию и определил, что ответственность является причиной для изменения.
Принцип Замещения Лискоу (Liskov's Substitution Principle)
Производные типы должны быть способны полностью замещаться их базовыми типами.
Этот принцип есть всего лишь расширение Принципа Открытости-Закрытости в условиях поведения, означающего, что мы должны быть уверены, что новые производные классы являются расширением базовых классов без изменения их поведения. Новые производные классы должны быть способны заменять базовые классы без каких-либо изменений в коде.
Принцип Замещения Лискоу был введён на 1987 Conference on Object Oriented Programming Systems Languages and Applications, in Data abstraction and hierarchy.
Last Updated ( Thursday, 27 March 2008 )
Оригинальный текст на английском языке взят из http://www.oodesign.com/design-principles.html
Знакомство с компилятором GCC
Одним из этих инструментов является компилятор GCC. Первоначально эта аббревиатура расшифровывалась, как GNU C Compiler. Сейчас она означает – GNU Compiler Collection.
Создадим первую программу с помощью GCC. По сложившейся традиции первая программа будет просто выводить в консоли приветствие «Hello world!» – «Здравствуй Мир!».
Файлы с исходными кодами программ, которые мы будем создавать, это обычные текстовые файлы, и создавать их можно с помощью любого текстового редактора (например GEdit KWrite, Kate, а также более традиционные для пользователей Linux – vi и emacs). Помимо текстовых редакторов, существуют специализированные среды разработки со своими встроенными редакторами. Одним из таких средств является KDevelop. Интересно, что в нём есть встроенный редактор и встроенная консоль, расположенная прямо под редактором. Так что можно прямо в одной программе, не переключаясь между окнами, и редактировать код и давать консольные команды.
Создайте отдельный каталог hello. Это будет каталог нашего первого проекта. В нём создайте текстовый файл hello.c со следующим текстом:
#include < stdio.h >
int main(void)
{
printf("Hello world!\n");
return(0);
}
Затем в консоли зайдите в каталог проекта. Наберите команду
gcc hello.c
Теперь посмотрите внимательно, что произошло. В каталоге появился новый файл a.out. Это и есть исполняемый файл. Запустим его. Наберите в консоли:
./a.out
Программа должна запуститься, то есть должен появиться текст:
Hello world!
Компилятор gcc по умолчанию присваивает всем созданным исполняемым файлам имя a.out. Если хотите назвать его по-другому, нужно к команде на компиляцию добавить флаг -o и имя, которым вы хотите его назвать. Давайте наберём такую команду:
gcc hello.c -o hello
Мы видим, что в каталоге появился исполняемый файл с названием hello. Запустим его.
./hello
Как видите, получился точно такой же исполняемый файл, только с удобным для нас названием.
Флаг -o является лишь одним из многочисленных флагов компилятора gcc. Некоторые другие флаги мы рассмотрим позднее. Чтобы просмотреть все возможные флаги, можно воспользоваться справочной системой man. Наберите в командной строке:
man gcc
Перед вами предстанет справочная система по этой программе. Просмотрите, что означает каждый флаг. С некоторыми из них мы скоро встретимся. Выход из справочной системы осуществляется с помощью клавиши q.
Вы, конечно, обратили внимание, что, когда мы запускаем программу из нашего каталога разработки, мы перед названием файла набираем точку и слэш. Зачем же мы это делаем?
Дело в том, что, если мы наберём только название исполняемого файла, операционная система будет искать его в каталогах /usr/bin и /usr/local/bin, и, естественно, не найдёт. Каталоги /usr/bin и /usr/local/bin – системные каталоги размещения исполняемых программ. Первый из них предназначен для размещения стабильных версий программ, как правило,входящих в дистрибутив Linux. Второй – для программ, устанавливаемых самим пользователем (за стабильность которых никто не ручается). Такая система нужна,чтобы отделить их друг от друга. По умолчанию при сборке программы устанавливаются в каталог /usr/local/bin. Крайне нежелательно помещать что-либо лишнее в /usr/bin или удалять что-то оттуда вручную, потому что это может привести к краху системы. Там должны размещаться программы, за стабильность которых отвечают разработчики дистрибутива.
Чтобы запустить программу, находящуюся в другом месте, надо прописать полный путь к ней, например так:
/home/dima/projects/hello/hello
Или другой вариант: прописать путь относительно текущего каталога, в котором вы в данной момент находитесь в консоли. При этом одна точка означает текущий каталог, две точки – родительский. Например, команда ./hello запускает программу hello, находящуюся в текущем каталоге, команда ../hello – программу hello, находящуюся в родительском каталоге, команда ./projects/hello/hello – программу во вложенных каталогах, находящихся внутри текущего.
Есть возможность добавлять в список системных путей к программам дополнительные каталоги. Для этого надо добавить новый путь в системную переменную PATH. Но давайте пока не будем отвлекаться от главной темы. Переменные окружения – это отдельный разговор.
Теперь рассмотрим, что же делает программа gcc. Её работа включает три этапа: обработка препроцессором, компиляция и компоновка (или линковка).
Препроцессор включает в основной файл содержимое всех заголовочных файлов, указанных в директивах #include. В заголовочных файлах обычно находятся объявления функций, используемых в программе, но не определённых в тексте программы. Их определения находятся где-то в другом месте: или в других файлах с исходным кодом или в бинарных библиотеках.
Вторая стадия – компиляция. Она заключается в превращении текста программы на языке C/C++ в набор машинных команд. Результат сохраняется в объектном файле. Разумеется, на машинах с разной архитектурой процессора двоичные файлы получаются в разных форматах, и на одной машине невозможно запустить бинарник, собранный на другой машине (разве только, если у них одинаковая архитектура процессора и одинаковые операционные системы). Вот почему программы для UNIX-подобных систем распространяются в виде исходных кодов: они должны быть доступны всем пользователям, независимо от того, у кого какой процессор и какая операционная система.
Последняя стадия – компоновка. Она заключается в связывании всех объектных файлов проекта в один, связывании вызовов функций с их определениями, и присоединением библиотечных файлов, содержащих функции, которые вызываются, но не определены в проекте. В результате формируется запускаемый файл – наша конечная цель. Если какая-то функция в программе используется, но компоновщик не найдёт место, где эта функция определена, он выдаст сообщение об ошибке, и откажется создавать исполняемый файл.
Теперь посмотрим на практике, как всё это выглядит. Напишем другую программу. Это будет примитивнейший калькулятор, способный складывать, вычитать, умножать и делить. При запуске он будет запрашивать по очереди два числа, над которыми следует произвести действие, а затем потребует ввести знак арифметического действия. Это могут быть четыре знака: «+», «–», «*», «/». После этого программа выводит результат и останавливается (возвращает нас в операционную систему, а точнее – в командный интерпретатор, из которого мы программу и вызывали).
Создадим для проекта новую папку kalkul, в ней создадим файл kalkul.c.
#include < stdio.h >
int main(void)
{
float num1;
float num2;
char op;
printf("Первое число: ");
scanf("%f",&num1);
printf("Второе число: ");
scanf("%f",&num2);
printf("Оператор ( + - * / ): ");
while ((op = getchar()) != EOF)
{
if (op == '+')
{
printf("%6.2f\n",num1 + num2);
break;
}
else if(op == '-')
{
printf("%6.2f\n",num1 - num2);
break;
}
else if(op == '*')
{
printf("%6.2f\n",num1 * num2);
break;
}
else if(op == '/')
{
if(num2 == 0)
{
printf("Ошибка: деление на ноль!\n");
break;
}
else
{
printf("%6.2f\n",num1 / num2);
break;
}
}
}
return 0;
}
Итак, первым делом, как было сказано, выполняется препроцессинг. Для того, чтобы посмотреть, что на этом этапе делается, воспользуемся опцией -E. Эта опция останавливает выполнение программы на этапе обработки препроцессором. В результате получается файл исходного кода с включённым в него содержимым заголовочных файлов.
В нашем случае мы включали один заголовочный файл – stdio.h – коллекцию стандартных функций ввода-вывода. Эти функции и выводили на консоль нужный текст, а также считывали с консоли вводимые нами слова.
Введите следующую команду:
gcc -E kalkul.c -o kalkul.cpp
Полученному файлу мы дали имя kalkul.cpp. Откройте его. Обратите внимание на то, что он весьма длинный. Это потому что в него вошёл весь код заголовочного файла stdio.h. Кроме того, препроцессор сюда добавил некоторые теги, указывающие компилятору способ связи с объявленными функциями. Основной текст нашей программы виден только в самом низу.
Можете заодно посмотреть, какие ещё функции объявлены в заголовочном файле stdio.h. Если вам захочется получить информацию о какой-нибудь функции, можно поинтересоваться о ней во встроенном руководстве man. Например, если вам вдруг захочется узнать, что же делает таинственная функция fopen, можно набрать:
man fopen
Много информации также есть в справочной системе info.
info fopen
Можно поинтересоваться и всем заголовочным файлом сразу.
man stdio.h
info stdio.h
Посмотрим теперь следующий этап. Создадим объектный файл. Объектный файл представляет собой «дословный» перевод нашего программного кода на машинный язык, пока без связи вызываемых функций с их определениями. Для формирования объектного файла служит опция -c.
gcc -c kalkul.c
Название получаемого файла можно не указывать, так как компилятор просто берёт название исходного и меняет расширение .c на .o (указать можно, если нам захочется назвать его по-другому).
Если мы создаём объектный файл из исходника, уже обработанного препроцессором (например, такого, какой мы получили выше), то мы должны обязательно указать явно, что компилируемый файл является файлом исходного кода, обработанный препроцессором, и имеющий теги препроцессора. В противном случае он будет обрабатываться, как обычный файл C++, без учёта тегов препроцессора, а значит связь с объявленными функциями не будет устанавливаться. Для явного указания на язык и формат обрабатываемого файла служит опция -x. Файл C++, обработанный препроцессором обозначается cpp-output.
gcc -x cpp-output -c kalkul.cpp
Наконец, последний этап – компоновка. Получаем из объектного файла исполняемый.
gcc kalkul.o -o kalkul
Можно его запускать.
./kalkul
Вы спросите: «Зачем вся эта возня с промежуточными этапами? Не лучше ли просто один раз скомандовать gcc kalkul.c -o kalkul?»
Дело в том, что настоящие программы очень редко состоят из одного файла. Как правило исходных файлов несколько, и они объединены в проект. И в некоторых исключительных случаях программу приходится компоновать из нескольких частей, написанных на разных языка. В этом случае приходится запускать компиляторы разных языков, чтобы каждый получил объектный файл из своего исходника, а затем уже эти полученные объектные файлы компоновать в исполняемую программу.
[ опубликовано 06/09/2006 ]
Дмитрий Пантелеичев (dimanix2006 at rambler dot ru) - Знакомство с компилятором GCCМатериал взят из http://www.linuxcenter.ru/lib/books/linuxdev/linuxdev1.phtml?style=print
Постоянные читатели
Архив блога
-
▼
2010
(55)
-
►
мая
(15)
- Прошёл сегодня первый тест по C++ на сайте www.ode...
- Разработка для iPhone на PHP и XML
- В сообществе фанатов Apple решили, что iPad нуждае...
- Finger Piano Share: 10 пианистов в одном iPhone
- Аналог Sleep (Win32) функции в Mac OS (iPhone OS)
- Дешевые издания приближают конец книги
- Ещё одно мнение об уровне квалификации программистов
- Сравнение строк вне зависимости от регистра символов
- Загадочные многоточия в ячейках TableView (UITable...
- Перенос C++ шаблонов из Visual C++ в Xcode-проекты...
- Утечки памяти в дополнительных потоках (в связи с ...
- Как скопировать файл стандартными средствами си++
- Как создать директорию
- Как получить в C++ список всех файлов из текущего ...
- Градации служебной карьеры программистов (junior, ...
-
►
апреля
(28)
- Стив Джобс рассказал, почему Apple "не пускает" Fl...
- Работа с локальным SVN-репозитарием
- Как в Mac OS снять блокировку/защиту из всех файло...
- Как получить пути к наиболее часто используемым па...
- Как автоматически копировать нужные заголовки в ну...
- Чем заменить функцию stricmp в iPhone-проекте
- Легендарный редактор vi
- Как выяснить причину EXC_BAD_ACCESS в Xcode
- Что делать, если в Xcode-отладчике невозможно пере...
- Как изменить размер стека потока средствами pthrea...
- Интересные материалы для C++ программистов в блоге...
- Принципы Agile Software Development
- Знакомство с компилятором GCC
-
►
мая
(15)