2016-05-15 16 views
6

Próbuję inaczej zaimplementować moją własną funkcję strcmp, moje strcmp bahaves, gdy używam znaków specjalnych.Implementacja strcmp nie działa ze znakami specjalnymi

#include <string.h>  

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

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

int main() 
{ 
    char *src = "a§bcDef"; 
    char *des = "acbcDef"; 
    printf("%d %d\n", my_strcmp(des, src), strcmp(des, src)); 
    return(0); 
} 

WYJŚCIE

161 -95

+3

Musisz zwrócić '* str2 - * str1' metinks. – fuz

+0

@FUZxxl kiedy to zrobię, otrzymuję '-161 i -95', nie jestem pewien, czy to prawda, ponieważ znak jest taki sam. –

+1

Jeśli znaki są zgodne, twoja funkcja działa poprawnie. – fuz

Odpowiedz

1

Oto co norma mówi o strcmp, z odpowiedniej części pogrubione:

oznaką niezerowej wartości zwracanej określa znak różnicy między wartości pierwszej pary bajtów (oba interpretowane jako niepodpisane znaki typu), które różnią się w porównaniu do łańcuchów o wartości .

Twój kod wykorzystuje różnicę bajtów jako char, która jeśli podpis jest różna od specyfikacji.

Zamiast:

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

Oto niektóre przypadki testowe dla oryginalnego kodu (my_strcmp), aktualnie akceptowanych odpowiedź z dasblinkenlight (my_strcmp1) i tej odpowiedzi (my_strcmp2). Tylko my_strcmp2 przechodzi testy.

#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; 
} 

(uwaga: I umieścić w jakiejś wyraźnej signed w implementacjach tak, że kod może być testowany na kompilatory z unsigned char). Przykro mi z powodu makra - to był szybki hack do przetestowania!

+0

Fajnie, naprawdę ... :-) – alk

+0

A jedynym niechlubnym twoim makrem wydaje się być parser źródłowy SO C ... ;-) – alk

3

char jest podpisany w wielu implementacjach, a realizacja strcmp uważa char wartości < 0 będzie mniejsza niż większa niż 0. Być może zamiast tego chcesz porównać wartości bez znaku.

const unsigned char *str1 = (unsigned char*) s1; 
const unsigned char *str2 = (unsigned char*) s2; 
Powiązane problemy