Страница 57 из 93 50. Не путайте привычность с читаемостью.
(Или синдром "настоящего программиста, который может программировать на любом языке как на ФОРТРАНе"). Многие люди пытаются злоупотреблять препроцессором для того, чтобы придать С большее сходство с каким-нибудь другим языком программирования. Например: #define begin { #define end } while ( ... ) begin // ... end Эта практика ничего не дает, кроме того, что ваш код становится нечитаемым для кого-нибудь, кто не знает того языка, который вы стараетесь имитировать. Для программиста на С код станет менее читаемым, не более того. Родственная проблема связана с использованием макросов препроцессора для скрытия синтаксиса объявлений С. Например, не делайте следующего: typedef const char *LPCSTR; LPCSTR str; Подобные вещи вызывают проблемы с сопровождением, потому что кто-то, не знакомый с вашими соглашениями, будет должен просматривать typedef, чтобы разобраться, что происходит на самом деле. Дополнительная путаница возникает в С++, потому что читатель может интерпретировать происходящее, как определение объекта С++ из класса LPCSTR. Большинству программистов на С++ не придет в голову, что LPCSTR является указателем. Объявления С очень легко читаются программистами на С. (Кстати, не путайте вышеупомянутое с разумной практикой определения типа word в виде 16-битового числа со знаком для преодоления проблемы переносимости, присущей типу int, размер которого не определен в ANSI С и С++). К тому же, многие программисты избегают условной операции (?:) просто потому, что она им кажется непонятной. Тем не менее, это условное выражение может существенно упростить ваш код и, следственно, сделать его лучше читаемым. Я думаю, что: printf("%s", str ? str : "?пусто>");гораздо элегантнее, чем: if ( str == NULL ) printf( "?пусто>" ); else printf( "%s", str ); Вы к тому же экономите на двух вызовах printf(). Мне также часто приходится видеть неправильное использование операций ++ и --. Весь смысл автоинкремента или автодекремента заключается в соединении этих операций с другими. Вместо: while ( *p ) { putchar ( *p ); ++p; } или: for ( ; *p ; ++p ) putchar ( *p ); используйте: while ( *p ) putchar ( *p++ ); Этот код вполне читаем для компетентного программиста на языке С, даже если ему нет эквивалентной операции в ФОРТРАНе или Паскале. Вы также никогда не должны прятать операторы в макросах из-за того, что вам просто не нравится, как они выглядят. Я однажды видел следующее в реальной программе: struct tree_node { struct tree_node *lftchld; }; #define left_child(x) ((x)->lftchld) //... traverse( tree_node *root ) { if ( left_child(root) ) traverse( left_child( root ) );// ... } Программист намеренно сделал определение структуры труднее читаемым для того, чтобы избежать конфликта имен между полем и совершенно необходимым макросом, и все из-за того, что ему не нравился внешний вид оператора ->. Для него было бы гораздо лучшим выходом просто назвать поле left_child и совсем избавиться от макроса. Если вы действительно думаете, что программа должна внешне выглядеть как на Паскале, чтобы быть читаемой, то вы должны программировать на Паскале, а не на С или С++. |