вторник, 19 июня 2012 г.

[prog.c] В догонку к Deep C (and C++)

…хотя зачастую на C/C++ нельзя написать нормальный код, если не иметь точных знаний на счет некоторых моментов. Совсем свежий пример, с пылу, с жару. Что не так в этом коде:

if(-1 == strcmp(a, b))…

Фиг знает почему, но у многих C/C++ разработчиков есть вбитая в подкорку уверенность в том, что strcmp возвращает всего три значения: -1, 0, +1. Хотя строго определено всего одно из них -- нулевое.

13 комментариев:

Unknown комментирует...

Эх, а первое что я вижу не так, это попытка сравнивать константу с переменной.

eao197 комментирует...

@Mastro Ombroj:

Это где здесь такое сравнение?

Unknown комментирует...

Иак вот же:
"если константа равна вызову функции"

eao197 комментирует...

@Mastro Ombroj:

Теперь понял о чем речь.

Имхо, в C/C++ есть несколько магических констант, которые лучше было бы использовать напрямую, не пряча за какими-либо макросами/именами/функциями. Тогда код читается проще.

Это как раз константы 0 и -1. AFAIK, -1 очень часто используется в низкоуровневом API для индикации ошибки. Это и привычно, и легко читается.

Если бы вдруг кто-нибудь спрятал значение -1 за именем LESS_THAN и написал бы:

if(LESS_THAN == strcmp(a,b))

то увидеть проблему было бы сложнее, на мой взгляд.

имя комментирует...

"вбитая в подкорку уверенность" видимо по аналогии с true=1 && false=0

а если чуть подумать, то си всегда ориентировался на скорость и делался давно, поэтому strcmp тогда возвращало, и думаю щас на не слишком навернутых процессорах тоже возвращает разность последних двух несовпадающих симвлов строки

int strcmp(const char* a, const char* b) {
      while( *a && *b && (*a == *b) )
            ++a, ++b;
      return (*a - *b);
}

кстати, подход "а как бы это делалось для скорости" позволяет запомнить много странностей си

имя комментирует...

и еще:

return (*a - *b);

верно и для беззнакового char, но приятнее читать было бы

return int(*a) - int(*b);

Анонимный комментирует...

man непрозрачно намекает:

RETURN VALUE
The strcmp() and strncmp() functions return an integer less than, equal
to, or greater than zero if s1 (or the first n bytes thereof) is found,
respectively, to be less than, to match, or be greater than s2.

eao197 комментирует...

@toshkaa:

Не очень понял к чему эта цитата из man-а. В документации нет утверждений о +1 и -1. А вот в головах у разработчиков такое утверждение откуда-то возникает.

Анонимный комментирует...

Цитата как источник достоверной информации о функции. +-1 там действительно нет, но она вполне возможна, хоть и не обязательна. А про разработчиков.. как-то не пришлось столкнуться с теми, кто так смело утверждает про +-1 не заглянув в документацию :) .

eao197 комментирует...

@toshkaa:

А про разработчиков.. как-то не пришлось столкнуться с теми, кто так смело утверждает про +-1 не заглянув в документацию

Ну а мне уже не один раз приходилось. Фрагмент кода из поста -- это выжимка из реального проекта, которому я делал code review (только что идентификаторы заменены).

Анонимный комментирует...

(Попытка реабилитации писавшего код :) ) Возможно автор опечатался (что не исключает того, что ошибка есть) и вместо <= поставил == . Тогда это превращается из невежества в обычную опечатку. Хотя программа, конечно, работает неправильно.

Анонимный комментирует...

т.е. >=

eao197 комментирует...

@toshkaa:

А вот это уже показатель уровня программиста. Начинающий программист будет пытаться сравнивать с -1, что черевато опечатками вроде <=, == или <. Тогда как если сравнивать только с нулем (единственным значением, точно указанным в документации), то ошибиться уже труднее. Разве что перепутать < с >.