реализация strcmp не работает со специальными символами

Я пытаюсь реализовать свой собственный

2 ответов


вот что говорит стандарт о strcmp С соответствующим разделом выделены жирным шрифтом:

знак ненулевого возвращаемого значения определяется знаком о разнице между значениями первой пары байтов (оба интерпретируется как тип unsigned char) которые отличаются тем, что строки сравнимый.

ваш код принимает разницу в байтах char, который при подписании отличается от спекуляция.

вместо:

return (unsigned char)(*str1) - (unsigned char)(*str2);

вот несколько тестовых примеров для исходного кода (my_strcmp), принятый в настоящее время ответ dasblinkenlight (my_strcmp1), и этот ответ (my_strcmp2). Только my_strcmp2 проходит испытания.

#include <string.h>
#include <stdio.h>

int my_strcmp(const char *s1, const char *s2) {
    const signed char *str1 = (const signed char*)(s1);
    const signed char *str2 = (const signed char*)(s2);

    while ((*str1 == *str2) && *str1)
    {
        str1++;
        str2++;
    }
    return (*str1 - *str2);
}

int my_strcmp1(const char *s1, const char *s2) {
    const signed char *str1 = (const signed char*)(s1);
    const signed char *str2 = (const signed char*)(s2);

    while ((*str1 == *str2) && *str1)
    {
        str1++;
        str2++;
    }
    return (signed char)(*str1 - *str2);
}

int my_strcmp2(const char *s1, const char *s2) {
    const signed char *str1 = (const signed char*)(s1);
    const signed char *str2 = (const signed char*)(s2);

    while ((*str1 == *str2) && *str1)
    {
        str1++;
        str2++;
    }
    return (unsigned char)(*str1) - (unsigned char)(*str2);
}


int sgn(int a) {
    return a > 0 ? 1 : a < 0 ? -1 : 0;
}

#define TEST(sc, a, b) do { \
    if (sgn(sc(a, b)) != sgn(strcmp(a, b))) { \
        printf("%s(%s, %s) = %d, want %d\n", #sc, a, b, sc(a, b), strcmp((const char*)a, (const char*)b)); \
        fail = 1; \
    } } while(0)

int main(int argc, char *argv[]) {
    struct {
        const char *a;
        const char *b;
    }cases[] = {
        {"abc", "abc"},
        {"\x01", "\xff"},
        {"\xff", "\x01"},
        {"abc", "abd"},
        {"", ""},
    };
    int fail = 0;
    for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
        TEST(my_strcmp, cases[i].a, cases[i].b);
        TEST(my_strcmp1, cases[i].a, cases[i].b);
        TEST(my_strcmp2, cases[i].a, cases[i].b);
    }
    return fail;
}

(Примечание: я вставил некоторые явные signed в реализациях, чтобы код можно было протестировать на компиляторах с неподписанным char). Кроме того, извините за макрос - это был быстрый хак для тестирования!


char подписывается во многих реализациях, а ваш strcmp реализация считает char значения

const unsigned char *str1 = (unsigned char*) s1;
const unsigned char *str2 = (unsigned char*) s2;