2016-05-15 5 views
6

Sto cercando di implementare la mia funzione strcmp, il mio strcmp bahaves in modo diverso quando utilizzo caratteri speciali.implementazione strcmp che non funziona con caratteri speciali

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

USCITA

161 -95

+3

È necessario restituire methinks '* str2 - * str1'. – fuz

+0

@FUZxxl quando lo faccio, ottengo '-161 e -95', non sono sicuro se, è giusto perché il segno è lo stesso. –

+1

Se i segni corrispondono, la tua funzione funziona correttamente. – fuz

risposta

1

Ecco ciò che la norma dice di strcmp, con una sezione rilevante evidenziato in grassetto:

Il segno di un valore di ritorno diverso da zero è determinata dal segno della differenza tra il valori della prima coppia di byte (entrambi interpretati come tipo unsigned char) che differiscono nelle stringhe di rispetto.

Il codice sta prendendo la differenza dei byte come char, che se firmato differisce dalle specifiche.

Invece:

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

Ecco alcuni casi di test per il codice originale (my_strcmp), la risposta attualmente accettata di dasblinkenlight (my_strcmp1), e questa risposta (my_strcmp2). Solo il my_strcmp2 supera i test.

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

(nota: ho messo in qualche esplicita signed nelle implementazioni in modo che il codice può essere testato su compilatori con unsigned char). Inoltre, mi dispiace per la macro - questo è stato un trucco veloce da testare!

+0

Bello, davvero ... :-) – alk

+0

E l'unico a cui non piace la tua macro sembra essere il parser SO C sorgente ... ;-) – alk

3

char viene firmato in molte implementazioni, e l'implementazione strcmp considera char valori < 0 ad essere più piccoli di quelli maggiore di 0. Forse vuoi confrontare i valori senza segno.

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