интересный сбой реализации strcmp. (С)

Я работаю над небольшим проектом, в котором у меня нет доступа к какой-либо стандартной библиотеке C (создание микроядра в структуре ARM с нуля. Даже printf пришлось реализовать)

В этом случае я реализовал strcmp, используя машинную методологию Даффа.

ниже приведен весь код.

int
strcmp ( const char *str1, const char *str2 )
{
   while ( *str1 || *str2 )
       if ( *(str1++) != *(str2++) ) return *str1 - *str2;
   return 0;
}

Это имело смысл; и какое-то время казалось, что это работает на тестовых примерах, пока не произошел сбой конечной системы. Я проследил вниз и пришел к этому strcmp.

Сначала я подумал, что сначала увеличивается str1, а затем сравнивается с str2 ДО увеличения str2. <сильный>1. Оказалось, что это не так, но кто-нибудь может подтвердить, что это может происходить в некоторых случаях?

Затем я решил, что проблема была в *str1 - *str2, поэтому изменил его, чтобы он возвращал 1. т. е. результирующий код выглядит следующим образом:

   while ( *str1 || *str2 )
       if ( *(str1++) != *(str2++) ) return 1;
   return 0;

в то время как все, что я хотел, это проверка «равно», поэтому изменение на «1» не вызвало проблем, но я все еще удивляюсь, почему исходный код не сработал. <сильный>2. Может ли кто-нибудь подсказать или подсказать, как это могло потерпеть неудачу? Я бы предпочел, чтобы strcmp следовал стандартному интерфейсу C, возвращая ненулевое значение, которое больше говорит о str1 и str2.

тестовые случаи были:

code_t // a function pointer type
program_find ( char *program )
{
if (strcmp( program, "exit" ) == 0) return ....
else if (strcmp( program, "k1" ) == 0) return ....
else if (strcmp( program, "k3" ) == 0) return ....
else if (strcmp( program, "perf" ) == 0) return ....
else if (strcmp( program, "test_libc" ) == 0) return ....
}

когда *program была "k3", она возвращала "k1", а "test_libc" возвращала "perf".

Первоначальная проблема была решена путем предоставления ей «возврата 1», поэтому этот вопрос касается исключительно интересов C. Также приветствуется предложение или ссылка на документацию strcmp. Я видел спецификацию интерфейса для IEEE


person Jace Kim    schedule 16.10.2011    source источник
comment
Что происходит, когда строки имеют разную длину?   -  person Kerrek SB    schedule 17.10.2011
comment
все строки заканчиваются нулем по предположению, поэтому они будут проверены, потому что вы сравниваете с нулевым символом в конце.   -  person Jace Kim    schedule 17.10.2011
comment
проверьте pdclib.rootdirectory.de , (неполную) реализацию стандартной библиотеки C99 с нуля; реализации функций из string.h можно найти здесь: pdclib.rootdirectory.de /trac.fcgi/browser/trunk/functions/   -  person Christoph    schedule 17.10.2011


Ответы (3)


Вы используете приращение поста на str1 и str2 при сравнении. Это приводит к тому, что они увеличиваются перед выполнением вычитания, поэтому вы вычитаете два неправильных символа.

Лучшей реализацией будет

int
strcmp ( const char *str1, const char *str2 )
{
   while ( *str1 || *str2 ) {
       if ( *str1 != *str2 ) return *str1 - *str2;
       ++str1;
       ++str2;
   }
   return 0;
}
person Vaughn Cato    schedule 16.10.2011

У вас две проблемы:

  • Вы увеличиваете указатели перед выполнением вычитания возвращаемого значения, поэтому возвращаемое значение неверно;
  • Стандарт, специфичный для strcmp(), указывает, что элементы строк сравниваются как unsigned char.

Исправление этих проблем:

int
strcmp ( const char *str1, const char *str2 )
{
    const unsigned char *s1 = (const unsigned char *)str1;
    const unsigned char *s2 = (const unsigned char *)str2;

    while (*s1 && *s1 == *s2) {
        s1++;
        s2++;
    }

    return *s1 - *s2;
}
person caf    schedule 16.10.2011
comment
вам нужно только проверить *s1 или *s2 на ноль, потому что в другом случае проверка на равенство не пройдет; см. pdclib.rootdirectory.de/trac.fcgi/browser /trunk/functions/ для эталонной реализации от DevSolar - person Christoph; 17.10.2011

Оценка выражения:

*(str1++) != *(str2++)

Разыменует указатели str1 и str2, сравнит результаты, затем увеличит оба указателя. К тому моменту, когда возвращается strcmp, они теперь указывают на что-то отличное от того, что вы сравнивали.

Имейте в виду, что реализация strcmp, которая всегда возвращает 1 или 0, сделает его бесполезным для сортировки списка строк! Вам нужно вернуть -1/0/+1, чтобы его можно было использовать для этого.

person Community    schedule 16.10.2011
comment
Ах я вижу. поэтому попытка *(str1++) != *(++str2) не удалась. - person Jace Kim; 17.10.2011