Forum: PC-Programmierung strcmp() aus musl libc


von zitter_ned_aso (Gast)


Lesenswert?

Hallo,

ich habe die Funktion strcmp(...) aus musl libc

http://git.musl-libc.org/cgit/musl/tree/src/string/strcmp.c

mit der gleichen Funktion aus glibc

https://github.com/bminor/glibc/blob/master/string/strcmp.c

verglichgen.

Beide rechnen mit "unsigned char". Aber macht diese return-Anweisung aus 
musl-libc Sinn?
1
return *(unsigned char *)l - *(unsigned char *)r;
Wegen integer promotion wird doch die Subtraktion mit int's durchgeführt 
und dann das Ergebnis einem int-Rückgabewert zugewiesen. Also ist diese 
Typumwandlung an dieser Stelle gar nicht nötig.

Bei glibc wird ja gleich zu Beginn umgewandelt. Aber erst bei einer 
return-Aweisung? Das ist doch gar nicht nötig oder?

von Oliver S. (oliverso)


Lesenswert?

zitter_ned_aso schrieb:
> Wegen integer promotion wird doch die Subtraktion mit int's durchgeführt

Mal ganz generell gefragt: was genau hast du eigentlich mit der lib vor? 
Nutz die, wie sie ist, oder lass es.

Oliver

: Bearbeitet durch User
von zitter_ned_aso (Gast)


Lesenswert?

Mal generell gefragt warum nein? Alles war "unter" int ist, wird bei 
Berechnungen als int / unsigned int  betrachtet oder nicht?

von foobar (Gast)


Lesenswert?

Überleg dir, was bei Zeichen außerhalb des Bereichs 0-127 passiert.

von Carl D. (jcw2)


Lesenswert?

In der gnu-Version fallen mir unnötige casts auf, um const zu entfernen. 
Aber c1/c2 werden nie verändert. Die musl-Variante ist zwar sehr knapp 
gehalten, aber frei von solchen "Unzulänglichkeiten". Und der cast auf 
unsigned Char wird gebraucht, um Zeichen >127 korrekt zu vergleichen.

von zitter_ned_aso (Gast)


Lesenswert?

zitter_ned_aso schrieb:
> return *(unsigned char *)l - *(unsigned char *)r;
> Wegen integer promotion wird doch die Subtraktion mit int's durchgeführt
> und dann das Ergebnis einem int-Rückgabewert zugewiesen. Also ist diese
> Typumwandlung an dieser Stelle gar nicht nötig.

nach langem Überlegen:

Integer promotion findet natürlich statt. Allerdings werden da falsche 
Zahlen zu Integer's befördert weil es bei den Buchstaben mit dem 
ASCII-Code > 127 einen Überlauf gibt (bei signed char). Und diese, 
falsche Zahl, wird nach "int" umgewandelt.

Bei mir funktioniert's übrigens auch wenn BEIDE Buchstaben >127 sind 
ohne explizite Typumwandlung.
1
return *l - *r;

Dann gibt es ja für beide einen Überlauf, aber der Abstand bleibt ja 
trotzdem gleich. Aber so ein Überlauf ist ja bei signed-Werten nicht 
definiert.Wenn es nur bei einem Buchstaben diesen Überlauf gibt, dann 
geht die Version ohne explizites Casten in die Hose.

Und dann habe ich noch eine Frage:
Warum wird die erste Variante akzeptiert und bei der zweiten - gewarnt?
1
 char str1[]="ü";                                                  
2
 char str2[]={'ü','\0'};

von Carl D. (jcw2)


Lesenswert?

zitter_ned_aso schrieb:
>
> Bei mir funktioniert's übrigens auch wenn BEIDE Buchstaben >127 sind
> ohne explizite Typumwandlung.
>

Aber manchmal hat man <=127/>127 gemischt.
Z.B. "aaaa" vs. "ääää". Was sagt dann dein Algorithmus?

: Bearbeitet durch User
von zitter_ned_aso (Gast)


Lesenswert?

Carl D. schrieb:
> Z.B. "aaaa" vs. "ääää"

na dann bekomme ich ein falsches Ergebnis, habe ich doch oben 
geschrieben.


bei 'a' gibt es keine Überlauf, bei 'ä' schon.

zitter_ned_aso schrieb:
> Wenn es nur bei einem Buchstaben diesen Überlauf gibt, dann
> geht die Version ohne explizites Casten in die Hose.

von foobar (Gast)


Lesenswert?

Es gibt nirgendwo einen Überlauf.

Du hast ein 8-Bit-Muster und je nach Interpretation entspricht das 
-128..127 (signed char) oder 0..255 (unsgined char).  Die Erweiterung 
nach int ist in beiden Fällen eindeutig definiert und die folgende 
(int-)Subtraktion erfolgt ohne Überlauf, liefert aber je nach 
Interpretation unterschiedliche Ergebnisse.

ANSI-C verlangt bei strcmp (und auch bei memcmp) die 
unsigned-Interpretation.

von zitter_ned_aso (Gast)


Lesenswert?

Warum ist das kein Überlauf?

Ich kann das ja sogar nachbilden:
1
    int i=225;                                                          
2
    char ch=i; //Ueberlauf, da char==signed char                        
3
    int i_wrong = ch;                                                   
4
                                                                        
5
    printf("\ngegebener Integerwert: \t%d\n", i);                       
6
    printf("falscher Integerwert: \t%d\n", i_wrong);                    
7
    printf("Ueberlauf von  char: \t%d\n", ch);                          
8
    printf("auf uchar gecastet: \t%u\n", (unsigned char)ch);            
9
    printf("Ueberlauf berechnet: \t%d\n\n", (i%128)+(-128));

und die Ausgabe (bei mir):
1
gegebener Integerwert:  225
2
falscher Integerwert:   -31
3
Ueberlauf von  char:    -31
4
auf uchar gecastet:     225
5
Ueberlauf berechnet:    -31

von foobar (Gast)


Lesenswert?

> Warum ist das kein Überlauf?

Äppel und Birnen?  Du wandelst von int nach char, strcmp von char nach 
int.

von Rolf M. (rmagnus)


Lesenswert?

zitter_ned_aso schrieb:
> Warum ist das kein Überlauf?

Es ist einfach nur eine andere Interpretierung der Bits.

Übrigens gibt es in C per Definition keine Überläufe.

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Rolf M. schrieb:
> Übrigens gibt es in C per Definition keine Überläufe.

Quelle bitte.

leo

von zitter_ned_aso (Gast)


Lesenswert?

zitter_ned_aso schrieb:
> char str1[]="ü";
>  char str2[]={'ü','\0'};

so, als hex-Code geht's:
1
 char str2[]={'\xFC','\0'};

aber in der Console wird dann
1
<fc>

angezeigt. Im string werden die Zeichen aus dem erweiterten 
ASCII-Zeichensatz direkt akzeptiert, als einzelne char's jedoch nicht 
(egal ob signed/unsigned). Diese muss man dann codiert eingeben oder 
wchar nutzen.

von Rolf M. (rmagnus)


Lesenswert?

leo schrieb:
> Rolf M. schrieb:
>> Übrigens gibt es in C per Definition keine Überläufe.
>
> Quelle bitte.

Aus ISO/IEC 9899. Ok, stimmt nicht ganz. Bei Gleitkomma-Typen kann es 
Überläufe geben.

Zu unsigned Integern:

"A computation involving unsigned operands can never overflow,
because a result that cannot be represented by the resulting unsigned 
integer type is reduced modulo the number that is one greater than the 
largest value that can be represented by the resulting type."

Bei vorzeichenbehafteten Integern darf man nicht auf einen Überlauf 
vertrauen, da das Verhalten undefiniert ist. Dazu hab ich direkt keine 
Passage gefunden, außer vielleicht dieser:

"If an exceptional condition occurs during the evaluation of an 
expression (that is, if the result is not mathematically defined or not 
in the range of representable values for its type), the behavior is 
undefined.

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Rolf M. schrieb:
> Zu unsigned Integern:

Du hattest nur diese gemeint oder auch signed integer? Bei letzteren 
gibt es sicher Overflow.
1
$ pdftotext c-std-n1256.pdf - | grep -c overflow
2
33

leo

von Rolf M. (rmagnus)


Lesenswert?

leo schrieb:
> Rolf M. schrieb:
>> Zu unsigned Integern:
>
> Du hattest nur diese gemeint oder auch signed integer?

Hatte ich doch geschrieben:

Rolf M. schrieb:
> Bei vorzeichenbehafteten Integern darf man nicht auf einen Überlauf
> vertrauen, da das Verhalten undefiniert ist.

leo schrieb:
> $ pdftotext c-std-n1256.pdf - | grep -c overflow
> 33

Das Wort "overflow" kommt schon vor, dennoch ist es so, dass unsigned 
integer nicht überlaufen können und ein Überlaufverhalten für 
signed-Integer nicht definiert ist.

von leo (Gast)


Lesenswert?

Rolf M. schrieb:
> und ein Überlaufverhalten für
> signed-Integer nicht definiert ist.

Ja, haette ich genauer lesen muessen. Wie auch immer Overflow passiert 
;)

leo

von Jemand (Gast)


Lesenswert?

1
7.17.7.5 The atomic_fetch and modify generic functions
2
[...]
3
For signed integer types, arithmetic is defined to use two’s
4
complement representation with silent wrap-around on overflow; there are no undefined
5
results.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.