Google
 
Главная1-й курс3-й курс4-й курс5-й курсСпецкурсыСсылкиКарта(версия для печати)

Об одной неочевидной ошибке в реализации функции strcmp

А. А. Вылиток

Оказалось, что некоторые студенты при выполнении упражения по реализации библиотечной функции сравнения двух строк int  strcmp ( const char *s1, const char *s2 ) забывают учесть машинное представление символьного типа в стандарте языка Си.

Итак, есть задача:

«Реализовать функцию int strcmp ( const char *s1, const char *s2 ), которая сравнивает две строки и возвращает 0, если строки равны; значение больше нуля, если первая строка больше второй; меньше нуля — если, соответственно, меньше. Считать, что коды символов в используемой реализации Си-машины упорядочены по алфавиту».

А вот пример решения:

int strcmp ( const char *s1, const char *s2 )
{
    for( ; *s1 == *s2; ++s1, ++s2 )
        if ( *s2 == '\0' )
            return 0;
    return *s1 - *s2;
}

Здесь ошибка в случае, когда в используемой реализации поведение char как целого типа совпадает с signed char (по стандарту char обязан совпадать либо с signed char, либо с unsigned char — это определяется реализацией), и в операторе return *s1 − *s2; код символа *s1 меньше 128, а код символа *s2 больше 127. Тогда при целочисленном расширении малых знаковых целых до int (по стандарту во всех операциях малые целые расширяются до int или unsigned int) получим вычитание из положительного числа отрицательного — результат будет положительный, что не удовлетворяет условию задачи.

Та же ошибка произойдет, если использовать фрагмент вида:

if ( *s1 > *s2 ) 
    return  1;
else
    return -1;

Поскольку при сравнении значений char также происходит целочисленное расширение до int (promotion), слева от > будет неотрицательное число, а справа — отрицательное.

Исправить ситуацию можно явным приведением типа:

return (unsigned char) *s1 - (unsigned char) *s2;

или соответственно

if ( (unsigned char) *s1 > (unsigned char) *s2 )
    return  1;
else
    return -1;

Более того, оказывается, опубликованная в книге K&R реализация strcmp обладает таким же недостатком.