Gibt es Probleme bei diesem Code?

2 Antworten

Sieht fehlerfrei aus. Nur zwei Anmerkungen:

  1. sizeof(char) ist per Definition = 1. Du kannst das weglassen.
  2. sizeof(str)−1 passt hier nur, weil str als Array definiert und genau so groß wie der enthaltene String (mit "\0") ist. Wenn Du den String mit "Tom" überschreibst, wird "an\0moT" ausgegeben. Und wenn du das in einer Funktion machst, bekommst Du nur die Größe des Zeigers, also 4 oder 8. Mit strlen(str) bist Du auf der sicheren Seite, denn das klappt in allen Fällen.

KarlRanseierIII  12.05.2023, 20:50
Wenn Du den String mit "Tom" überschreibst

ist undefined behavior die Konsequenz.

0
KarlRanseierIII  12.05.2023, 23:46
@ralphdieter

Oh, Du scheinst recht zu haben, gcc packt die Literale auf den Stack und scheint das wie VLAs zu behandeln.

Das ist interessant, denn AFAIK müssen Stringliterale nicht "distinct" sein.

Nutze ich char* landen sie in .rodata und teilen sich mitunter auch den gleichen Speicherort. Das c++ Frontend sagt auch, daß die Konversion verboten sei.

----

Da habe ich wohl zu schnell geschossen ...

0
KarlRanseierIII  12.05.2023, 23:55
@KarlRanseierIII

Humm....

In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals.
The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence.

Im Folgenden heißt es dann:

It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

Lassen die Compiler hier also nur Gnade vor Recht ergehen?

0
ralphdieter  13.05.2023, 16:24
@KarlRanseierIII

Das bezieht sich bestenfalls auf das Stringliteral, mit dem das Array bei jedem Aufruf initialisiert wird. Falls das gleiche Literal anderswo als char * verwendet wird, darf der Compiler (oder Linker) die beiden zusammenfassen. Und wenn letzteres überschrieben wird, wirkt sich das auf die nächste Initialisierung des Arrays aus – UB in Reinform eben.

1
KarlRanseierIII  13.05.2023, 21:00
@ralphdieter

Die Sache ist die, bei

char somename[128]="Some Text";

Ist klar, daß das Feld mit dem Stringliteral (durch kopieren?) initialisiert wird.

char a[]; /* a has incomplete type */
char a[]="Some Text";

Für das Literal gilt das zuvor zitierte. Nur ohne Größe ist a doch im besten Fall ein VLA, während es sonst als char * interpretiert wird. Also warum darf der Compiler hier a nicht in eine ro-Seite ohne uniqueness zeigen lassen?

Vielleicht habe ich es überlesen.

Übrigens, clang platziert die Literale nur dann in .text auf dem Stack, wenn ich hingehe und sie verändere, sonst platziert er im Gegensatz zu gcc in .rodata und lässt dorthin zeigen.

0
ralphdieter  13.05.2023, 23:35
@KarlRanseierIII
ohne Größe ist a doch im besten Fall ein VLA

Die Größe wird durch den Initialisierer festgelegt. N1256 sagt dazu:

6.7.8 Initialization

[...]
(14) An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
[...]
(22) If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. At the end of its initializer list, the array no longer has incomplete type.
[...]
(32) EXAMPLE 8 The declaration
char s[] = "abc", t[3] = "abc";
defines ‘‘plain’’ char array objects s and t whose elements are initialized with character string literals. This declaration is identical to
char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
The contents of the arrays are modifiable. On the other hand, the declaration
char *p = "abc";
defines p with type ‘‘pointer to char’’ and initializes it to point to an object with type ‘‘array of char’’ with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
1
KarlRanseierIII  14.05.2023, 00:04
@ralphdieter

Okay, das ergibt Sinn, ich hatte nicht dran gedacht, daß der Initializer implizit den unvollständigen Typ komplettiert und die Feldgröße fixiert.

(22) war das, was ich wohl übersehen hatte.

Danke für den Gedankenaustausch respektive den Input.

0
ralphdieter  13.05.2023, 23:57

@Deadlock:

eben fällt mir doch ein Bug auf:

sizeof(str)−1 ist hier 6, weil das abschließende '\0' auch zählt. Deine Schleife zählt also von 6 bis 0 runter, und im ersten Durchlauf gibst Du str[6] aus. Ändere mal das Format von "%c" auf "%2x ", dann siehst Du das Problem.

1
ralphdieter  14.05.2023, 00:00

Und noch etwas:

int i = sizeof(...)

müsste mindestens eine Compilerwarnung ergeben, weil sizeof() unsigned ist.

1
KarlRanseierIII  14.05.2023, 00:27
@ralphdieter

Ne, keine Warnung.

Zumindest nicht mit einem einfachen -Wall, -Wextra, habs gerade mal getestet - wenn Du es allerdings mit nem falschen Format specifier ausgeben willst, dann warnt er *lach*.

Korrekterweise sollte es

size_t i = sizeof(...);

lauten.

0
ralphdieter  14.05.2023, 01:25
@KarlRanseierIII

Jepp, aber dann muss man bei der Abbruchbedingung aufpassen, denn i>=0 ist immer erfüllt. Ich mach da gern:

for (size_t i = N; i-- > 0; ) /* von N-1 bis 0 */
0

Je nach Datentyp ist "0" minus eins wieder >0
und dann wäre dies eine Endlosschleife.


Deadlock 
Fragesteller
 12.05.2023, 17:48

Also wenn ich str = ““; vorher machen würde oder

0
IchMalWiederXY  12.05.2023, 17:55
@Deadlock

-Einen Datentyp wählen der negative Zahlen kann.
Hier diverse Lösungen in Java.
In "C" findest du ebenfalls im Web Lösungen dazu.

0
Deadlock 
Fragesteller
 12.05.2023, 17:56
@IchMalWiederXY

? Ich will doch strings reversen und da wäre das kleinste „“ weniger geht nicht kannst du überhaupt programmieren

0
IchMalWiederXY  13.05.2023, 17:05
@Deadlock

Dein Schleifenabbruch ist i>=0
0-1 = -1 "eigentlich" und du würdest aussteigen aus der "for" loop.
ABER der Datentyp "int" ist je nach Plattform anders definiert.
er ist typisch 16 Bit und geht von 0<->65535
oder -32768<->+32767
Wenn bei einem Datentyp, der NUR positive Zahlen kennt von der 0 'eins' abgezogen wird dann landest du im Falle von 'int'
0-1= 65535
und damit wieder >=0 und die Schleife bricht nicht ab.
ALSO. Beschäftige dich mit Datentypen um bei Abbruchbedingungen aus Schleifen die Implementierung robust zu haben.

0
Deadlock 
Fragesteller
 13.05.2023, 23:21
@IchMalWiederXY

Ne bei C klappt das, das machen alle so Bruh, Datentypen sind unwichtig eigentlich Python hat ja an sich gar keine

0
IchMalWiederXY  14.05.2023, 09:09
@Deadlock

"Datentypen sind unwichtig eigentlich".
..wegen falschem Datentyp ist die Ariane Rakete abgestürzt.
Je nach dem in welchem Umfeld programmiert wird, ist deren "korrekte" Wahl Basis für Erfolg oder Misserfolg.
..und ich hätte es anders programmiert.

0
Deadlock 
Fragesteller
 14.05.2023, 10:41
@IchMalWiederXY

hmm also das waren gute Programmierer die das mit der Rakete programmiert haben, von daher bedeutet das, dass sehr intelligente Menschen falsche Datentypen wählen

0