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

#c #pointers #character #strcmp #c-strings

#c #указатели #символ #strcmp #c-строки

Вопрос:

Я работаю над небольшим проектом, к которому у меня нет доступа ни к одной стандартной библиотеке 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, поэтому изменил его на return 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».

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

Комментарии:

1. Что происходит, когда строки имеют неодинаковую длину?

2. все строки имеют нулевое завершение по предположению, поэтому оно будет проверено, потому что вы сравниваете с нулевым символом в конце.

3. проверьте pdclib.rootdirectory.de , (неполная) реализация стандартной библиотеки C99 с нуля; реализации функций из string.h можно найти здесь: pdclib.rootdirectory.de/trac.fcgi/browser/trunk/functions /…

Ответ №1:

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

Лучшей реализацией было бы

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

Ответ №2:

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

  • Вы увеличиваете указатели перед выполнением вычитания для возвращаемого значения, поэтому возвращаемое значение неверно;
  • Стандарт, специфичный для 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 amp;amp; *s1 == *s2) {
        s1  ;
        s2  ;
    }

    return *s1 - *s2;
}
  

Комментарии:

1. вам нужно только проверить либо *s1 или *s2 на ноль, потому что в другом случае проверка равенства не пройдет; см. pdclib.rootdirectory.de/trac.fcgi/browser/trunk/functions /… для эталонной реализации DevSolar

Ответ №3:

Вычисление выражения:

 *(str1  ) != *(str2  )
  

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

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

Комментарии:

1. а, понятно. вот почему *(str1 ) != *( str2) попытка в конце концов не удалась.

Ответ №4:

 int strcmp(const char* a, const char* b){
    for(;;  a,  b){
        if(*a == '' || *b == '')
            return (*a == *b)? 0 : *a != '' ? 1 : -1;
        if(*a != *b) return (unsigned char)(*a) > (unsigned char)(*b) ? 1 : -1;
    }
}