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!
È necessario restituire methinks '* str2 - * str1'. – fuz
@FUZxxl quando lo faccio, ottengo '-161 e -95', non sono sicuro se, è giusto perché il segno è lo stesso. –
Se i segni corrispondono, la tua funzione funziona correttamente. – fuz