strcmp() aus musl libc

Gast #6188765
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?
#6188815
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.
Gast #6189158
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'};
Gast #6189278
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.
Gast #6189324
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
Gast #6189412
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.
#6189586
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.
#6189629
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.
Gast #6189678
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren