Программирование >>  Решение нетривиальных задач 

1 ... 36 37 38 [ 39 ] 40 41 42 ... 77


Часто необходимость в явном сравнении на истину или ложь можно устранить при помощи переименования:

if( я сонливIЙ(p) ) значительно лучше, чем:

if( я сонливIЙ(p) != FALSE )

Так как определения TRUE и FALSE спрятаны в макросах, то хороший сопровождающий программист не может делать каких-либо предположений об их действительных значениях. Например, FALSE может быть -1, а TRUE - 0. И следственно, если функция возвращает в явном виде TRUE или FALSE, то наш прилежный сопровождающий программист должен будет потратить несколько дней, чтобы убедиться, что при проверке возвращаемого значения для каждого вызова используется явная проверка на равенство TRUE или FALSE (сравните для примера с простым логическим отрицанием ! перед вызовом). Следующий фрагмент:

if( я сердитый() )

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

И напоследок - имейте в виду, что следующий вариант не будет работать:

#define FALSE 0 #define TRUE !FALSE

Операция !, подобно всем операторам отношений, преобразует операнд в 1, если он имеет значение истина (отличен от нуля), и 0, если наоборот. Предыдущий вариант идентичен следующему:

#define FALSE 0 #define TRUE 1

Вот более надежный, но нелепый вариант:

#define IS TRUE(x) ((x) == 0)

#define IS FALSE(x) ((x) != 0)



86. Для битового поля размером 1 бит должен быть определен тип unsigned

После того, как ANSI Си позволил назначать битовому полю знаковый тип, мне доводилось видеть код, подобный:

struct fred

int i : 1;

a fred;

Возможными значениями являются 0 и -1. Оператор типа:

#define TRUE 1 ...

if( a fred.i == TRUE ) ...

не будет работать, потому что поле a fred.i может иметь значение 0 или -1, но оно никогда не будет равняться 1. Следовательно, оператор if никогда не выполняется.

87. Указатели должны указывать на адрес, больший, чем базовый для массива

Это правило подтверждено стандартом ANSI Си, но многие программисты, похоже, не подозревают о том способе, которым язык должен работать. ANSI Си говорит, что указатель может переходить на ячейку, следующую после окончания массива, но он не может иметь величину меньше, чем базовый адрес массива. Нарушение этого правила может прервать программу, которую пытаются выполнить, например, в сегментной модели памяти процессоров 80x86. Следующий код не будет работать:

int array[ SIZE ];

int *p = array + SIZE; Здесь все в порядке; вы можете

двигаться дальше. while ( --p >= array ) Это не работает - возможен

бесконечный цикл.

...

Проблема состоит в том, что при сегментной архитектуре есть возможность того, что массив попадет на начало сегмента и получит исполнительный адрес 0x0 00 0. (В архитектуре 8086 это будет смещением - частью адреса любого байта, состоящего из адреса сегмента и смещения). Если p установлен на начало массива (0x0000), то операция -- p вызывает его перемещение на адрес 0xfffe (если у типа



int размер 2 байта), который считается большим, чем p. Другими словами, предыдущий цикл никогда не закончится. Исправьте эту ситуацию следующим образом:

while ( -- p >= array )

...

if ( p == array ) break;

Вы можете выйти из положения так:

int *p = array + (SIZE - 1);

...

} while ( p-- > array );

но позаботьтесь, чтобы p был внутри массива перед началом цикла. (Указатель должен быть инициализирован значением p+(SIZE-1), а не p+SIZE).

88. Используйте указатели вместо индексов массива

Вообще, инкрементирование указателя - лучший способ перемещения по массиву, чем индекс массива. Например, простой цикл, подобный следующему, страшно неэффективен:

struct thing

int field;

int another field;

int another field;

thing array[ nrows ][ ncols ]; int row, col;

for ( row = 0; row < nrows ; ++nrows ) for ( col = 0; col < ncols; ++cols ) array[row][col].field = 0;

Выражение array[row][col] требует двух умножений и одного сложения во время выполнения. Вот что происходит на самом деле:

array + (row * size of one row) + (col * size of a thing)

Каждая структура имеет размер 12 байтов, и 12 не является степенью 2, поэтому вместо умножения нельзя использовать более эффективный



1 ... 36 37 38 [ 39 ] 40 41 42 ... 77

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика