Информатика и технология программирования

         

" Подводные камни" и " маленькие хитрости"


Компактный синтаксис операций, а также их совместимость по результатам служат источником значительного количества ошибок такого плана: при пропуске или, наоборот, дублировании знака операции может получиться другая операция, которая при принятой в Си "свободе нравов" будет синтаксически корректна, выполнима, но даст совершенно незапланированный результат. "Сообразительный" транслятор может сопроводить такую ошибку предупреждением (WARNING). Приведем примеры таких ошибок:


if (a=b) // вместо if (a==b)


while (a &#60&#60 3) // вместо while (a &#60 3)


if (a &#38&#38 0x10) // вместо if (a &#38 0x10)

Трудно обнаруживаемые ошибки возникают при неявных преобразованиях типов в операциях, особенно при сочетании знаковой и беззнаковой форм представления:


char c[80];
&#35define CODE 193
if (c[i] == CODE) // Эквивалентно (int)c[i] == 193

В данном примере идентификатором CODE обозначена целая константа, которая имеет смысл кода символа, на наличие которого затем проверяются элементы массива символов. Но дело в том, что такая операция будет давать значение "ложь" всегда. Дело в том, что тип char представляет символы как знаковые байты (целые минимальной длины), поэтому этому коду в данной форме представления соответствует отрицательное значение - 63 . Так как любая операция преобразует операнды char к int , то получится интересное сочетание "-63 == 193", имеющее значение "ложь" вместо планируемого "истина". В таких случаях, когда разрядности переменных меняются, лучше не смешивать знаковую и беззнаковую формы. В данном случае исправить ошибку можно несколькими способами


&#35define CODE -63 // Непонятно




&#35define CODE (char)193 // Приемлемо


&#35define CODE '\301' //


unsigned char c[80]; // Лучше всего для символов с кодами &#62 128

При выполнении операций с переменными различной разрядности нужно помнить, что последовательность преобразования разрядностей (типов) связана с последовательностью и приоритетами выполнения операций.
Поэтому само по себе наличие в выражении операнда большей разрядности еще не гарантирует правильности вычислений для больших значений. Это видно на примере, где используется переменная типа
long для хранения произведения переменных типа int . Ошибка состоит в том, что операция умножения все равно будет производиться с целыми размерности int , что может привести к потере значащих цифр произведения:



int a,b; long c;
c = a * b; // Неправильно

c = (long)a * b; // Правильно

Операция присваивания, операция "
запятая" и условная операция позволяют выполнять многие действия "на лету", не выходя за пределы синтaксиса выражения в условных выражениях оперaторов if, while , например:



while ((c=getchar()) !='*') {...c...}

Здесь в переменной c запоминается результат функции, вызванной во время проверки условия в операторе while, с целью дальнейшего его использования в теле оператора.



while (x0=x1, x0 &#62 0) {... x1 =f(x0) ...}

Присваивание выполняется во время проверки условия в операторе цикла.



for (...; d&#62 0 ? a&#62b : b&#62=a; ...) {...}

В зависимости от значения переменной d меняется условие продолжения цикла for .

При наличии в программе нескольких вариантов выбора по группе условий программа становится "сильно ветвистой", например:



if (a&#60b)
if (a&#60c)
if (b&#60c) {...} // a &#60 b &#38&#38 a &#60 c &#38&#38 b &#60 c

else {...} // a &#60 b &#38&#38 a &#60 c &#38&#38 b &#62=c

else
if (b&#60c) {...} // a &#60 b &#38&#38 a &#62=c &#38&#38 b &#60 c

else {...} // a &#60 b &#38&#38 a &#62=c &#38&#38 b &#62=c

else ...

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



int n; n = (a &#60 b)*4 + (a &#60 c)*2 + (b &#60 c);
switch(n)
{
case 0:... break; // a &#62=b &#38&#38 a &#62=c &#38&#38 b &#62=c

case 7: ... break; // a &#60 b &#38&#38 a &#60 c &#38&#38 b &#60 c

}


Содержание раздела