интересный сбой реализации strcmp.(С) - PullRequest
0 голосов
/ 17 октября 2011

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

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

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

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

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

Сначала я подумал, что сначала увеличивается 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 ....
}

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

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

Ответы [ 4 ]

7 голосов
/ 17 октября 2011

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

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

int
strcmp ( const char *str1, const char *str2 )
{
   while ( *str1 || *str2 ) {
       if ( *str1 != *str2 ) return *str1 - *str2;
       ++str1;
       ++str2;
   }
   return 0;
}
4 голосов
/ 17 октября 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;
}
1 голос
/ 17 октября 2011
int strcmp(const char* a, const char* b){
    for(;;++a,++b){
        if(*a == '\0' || *b == '\0')
            return (*a == *b)? 0 : *a != '\0' ? 1 : -1;
        if(*a != *b) return (unsigned char)(*a) > (unsigned char)(*b) ? 1 : -1;
    }
}
1 голос
/ 17 октября 2011

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

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

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

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

...