mikrocontroller.net

Forum: Compiler & IDEs strlen(.) oder sizeof(.)-1


Autor: Jochen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Was ist denn besser?
#define MY_STRING  "Das ist ein Test"

...
{
  uint8 len;
  /* Option 1 */
  len = strlen(MY_STRING);
  /* Option 2 */
  len = sizeof(MY_STRING)-1;
}


Danke & Gruß
Jochen

: Verschoben durch Moderator
Autor: Peter II (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Jochen schrieb:
> Was ist denn besser?

ordentlicher ist strlen, schneller ist sizeof

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> ordentlicher ist strlen, schneller ist sizeof

Kommt darauf an, ob strlen() eine externe Funktion ist oder "builtin" 
ist.

Der gcc generiert jedenfalls für beide Varianten denselben Code.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Peter II schrieb:
> ordentlicher ist strlen, schneller ist sizeof

In diesem speziellen Fall sind sie typischerweise gleichwertig.
Wenn man es allgemeiner betrachtet, muss man beachten, dass sizeof nur 
mit konstanten Arrays das gewünschte Ergebnis bringt, während strlen 
ganz allgemein mit Strings funktioniert, dafür aber (sofern der Inhalt 
dem Compiler nicht schon bekannt ist) zur Laufzeit durch den String 
iterieren muss und daher mehr Zeit braucht.

Autor: Jochen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> ordentlicher ist strlen, schneller ist sizeof

Habe ich vermutet, da der Compiler vermutlich schon das sizeof()-1 
ausrechnet und als festen Wert in den Code einträgt.

Das wird vermutlich auch bei
#define MY_STRING  "Das ist ein Test"

char testString[] = MY_STRING;
...
{
  uint8 len;
  /* Option 1 */
  len = strlen(MY_STRING);
  /* Option 2 */
  len = sizeof(MY_STRING)-1;
}

gelten, so lange man den Inhalt von testString nicht ändert.

Wenn ich das hier mache:
#define MY_STRING  "Das ist ein Test"

char testString[] = MY_STRING;
...
{
  uint8 len;
  
  testString[4] = 0;
  /* Option 1 */
  len = strlen(MY_STRING);
  /* Option 2 */
  len = sizeof(MY_STRING)-1;
}
Bekomme ich bei Option 1 logsicherweise dann 3 und Option2 weiterhin 
(konstant) 16.

Oder?

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jochen schrieb:
> Peter II schrieb:
>> ordentlicher ist strlen, schneller ist sizeof
>
> Habe ich vermutet, da der Compiler vermutlich schon das sizeof()-1
> ausrechnet und als festen Wert in den Code einträgt.

Ja, natürlich wird sizeof() immer zur Compilezeit ermittelt. Aber in 
Deinem konkreten Fall, wo es sich um eine Zeichenkonstante handelt, die 
zur Compilezeit bekannt ist, ersetzt der Compiler den Aufruf von 
strlen() direkt durch die Konstante.

Beweis:
#define MY_STRING  "Das ist ein Test"

int
main ()
{
    uint8_t len;

    len = strlen(MY_STRING);
//  len = sizeof(MY_STRING)-1;

    PORTD = len;   // damit das Ergebnis nicht wegoptimiert wird
}

Output:
00000080 <main>:
  80:  80 e1         ldi  r24, 0x10  ; 16
  82:  8b b9         out  0x0b, r24  ; 11
  84:  80 e0         ldi  r24, 0x00  ; 0
  86:  90 e0         ldi  r25, 0x00  ; 0
  88:  08 95         ret

Hier wird PORTD einfach mit 16 geladen. Das ist derselbe Code wie bei 
der sizeof-Variante.

: Bearbeitet durch Moderator
Autor: Daniel A. (daniel-a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sowas kann auch praktisch werden:
#include <stdio.h>
#define CS(X) (const string){ .ptr=X, .length=sizeof(X)-1 }

typedef struct {
  char* ptr;
  size_t length;
} string;

int main( void ){
  const string s = CS("Test");
  printf("%zu: ",s.length);
  fwrite(s.ptr,1,s.length,stdout);
  putchar('\n');
  return 0;
}

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und jetzt die Preisfrage: was passiert bei
#define MY_STRING  "Das ist ein Test\0und nochwas"

???

Autor: Georg G. (df2au)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> ???

sizeof() liefert die gesamte Länge, strlen() liefert die Länge bis zur 
ersten 0x00. Woher soll das Programm zur Laufzeit auch wissen, dass der 
Programmierer da höheren Schwachsinn geschrieben hat.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> und jetzt die Preisfrage: was passiert bei
> #define MY_STRING  "Das ist ein Test\0und nochwas"

strlen: 16
sizeof: 28

Beide Male setzt der Compiler einfach die Konstante in den 
Assembler-Code ein. strlen() wird also weiterhin nicht aufgerufen.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin immer wieder begeistert, was der Compiler alles weg optimieren 
kann. Dass er strlen() durch eine Konstante ersetzen kann hätte ich gar 
nicth erwartet. Ein super Programm ist das, ich mag den gcc.

Autor: Clemens L. (c_l)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für den "Hallo, Welt"-Benchmark gibt es natürlich auch etwas: 
http://www.ciselant.de/projects/gcc_printf/gcc_printf.html

Autor: Markus F. (mfro)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Georg G. schrieb:
> Markus F. schrieb:
>> ???
>
> sizeof() liefert die gesamte Länge, strlen() liefert die Länge bis zur
> ersten 0x00. Woher soll das Programm zur Laufzeit auch wissen, dass der
> Programmierer da höheren Schwachsinn geschrieben hat.

Das ist meiner Ansicht nach kein Schwachsinn (weder hoch noch tief) - 
ich verwende das beispielsweise für Texte, wenn ich nur zwei Sprachen 
brauche.

Wollte damit zeigen, daß sizeof() - 1 möglicherweise keine gute Idee als 
Ersatz für strlen() ist.

Autor: Dergute W. (derguteweka)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Moin,

Wenn man mal noch lustigere Zeichen als simples ASCII nimmt, also 
irgendwelche UTF-irgendwas Dinger, wirds wohl auch Abweichungen zwischen 
strlen und sizeof geben.

Gruss
WK

Autor: Dumdi D. (dumdidum)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
strlen ist besser, da es ausdrückt was gemeint ist. sizeof()-1 dauert 3x 
länger zu verstehen (ausser natürlich in so kleinen Programmen). Wenn 
das Programm mal geändert wird auf char* , dann liefert sizeof einen 
falschen Wert.

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan U. schrieb:
> Ich bin immer wieder begeistert, was der Compiler alles weg optimieren
> kann. Dass er strlen() durch eine Konstante ersetzen kann hätte ich gar
> nicth erwartet. Ein super Programm ist das, ich mag den gcc.

Der kann sogar die Funktionen aus math.h ersetzen, wenn man die mit 
Konstanten aufruft.

Autor: Georg G. (df2au)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> Wollte damit zeigen, daß sizeof() - 1 möglicherweise keine gute Idee als
> Ersatz für strlen() ist.

Genau das wollte ich auch sagen. Sizeof() wird nur zur Compile Zeit 
ausgewertet. Ich hätte erwartet, dass der Compiler bei einem String, der 
nicht als const definiert ist, das strlen() nicht als Funktion 
eliminiert. Im Gegensatz zu stefanus halte ich das für einen Fehler.

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg G. schrieb:
> Im Gegensatz zu stefanus halte ich das für einen Fehler.

Wenn der Compiler keinen Weg sieht, wie der String etwas anderes
als konstant sein kann, darf er das, ansonsten natürlich nicht.

Autor: Georg G. (df2au)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zur Klarstellung:

Bei den Beispielen wurde der String immer mit #define str "tralala" 
definiert. Damit kann er zur Laufzeit nie verändert werden.

Definiert man ihn mit char str[] = "tralala", wird strlen() immer 
aufgerufen.

: Bearbeitet durch User
Autor: Peter II (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Georg G. schrieb:
> Bei den Beispielen wurde der String immer mit #define str "tralala"
> definiert. Damit kann er zur Laufzeit nie verändert werden.
>
> Definiert man ihn mit char str[] = "tralala", wird strlen() immer
> aufgerufen.

das kann nicht sein.
Der Compiler sieht darin keinen Unterschied. der Preprozessor ersetzt ja 
schon die defines.

Autor: Georg G. (df2au)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> das kann nicht sein.

Dann probier es aus.

char str0[] = "Hello World";
#define str1 "tralala"

int main(void) {

    char    i;

    i = strlen(str0);
    PORTA = i;

    i = strlen(str1);
    PORTA = i;

    return(0);
    }

ergibt

    i = strlen(str0);
  be:  e0 e0         ldi  r30, 0x00  ; 0
  c0:  f1 e0         ldi  r31, 0x01  ; 1
  c2:  01 90         ld  r0, Z+
  c4:  00 20         and  r0, r0
  c6:  e9 f7         brne  .-6        ; 0xc2 <main+0x4>
  c8:  31 97         sbiw  r30, 0x01  ; 1
  ca:  e0 50         subi  r30, 0x00  ; 0
  cc:  f1 40         sbci  r31, 0x01  ; 1
    PORTA = i;
  ce:  e2 b9         out  0x02, r30  ; 2

    i = strlen(str1) -1;
    PORTA = i;
  d0:  86 e0         ldi  r24, 0x06  ; 6
  d2:  82 b9         out  0x02, r24  ; 2

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg G. schrieb:
> Dann probier es aus.
>
> char str0[] = "Hello World";

Hängt damit zusammen, dass str0 hier global sichtbar ist und daher
von anderen Modulen geändert werden könnte.

Mach es mal „static“.

Autor: Georg G. (df2au)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Mach es mal „static“.

Aber gern :-)

int main(void) {

static char str0[] = "Hello World";
    char    i;

    i = strlen(str0);
  be:  e0 e0         ldi  r30, 0x00  ; 0
  c0:  f1 e0         ldi  r31, 0x01  ; 1
  c2:  01 90         ld  r0, Z+
  c4:  00 20         and  r0, r0
  c6:  e9 f7         brne  .-6        ; 0xc2 <main+0x4>
  c8:  31 97         sbiw  r30, 0x01  ; 1
  ca:  e0 50         subi  r30, 0x00  ; 0
  cc:  f1 40         sbci  r31, 0x01  ; 1
    PORTA = i;
  ce:  e2 b9         out  0x02, r30  ; 2

Noch Fragen?

Autor: Carl D. (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg G. schrieb:
> Noch Fragen?

Welcher Compiler/Version?

Autor: Georg G. (df2au)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thread model: single
gcc version 4.7.2 (AVR_8_bit_GNU_Toolchain_3.4.2_939)

Autor: 2⁵ (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach mal ein 'const' davor ;-)

Autor: Carl D. (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geh mal auf 4.9 oder größer.
Nicht immer wurde mit neueren Versionen das AVR-Backend besser, aber der 
Compiler selbst hat massiv dazugelernt.
Ich verwende 6.2 und bin mir sicher, daß der keine Probleme hat, die 
Länge dieses faktisch konstanten Strings (statisch, nicht verändert) zur 
Compile-Time zu ermitteln.
Wobei, wenn man weiß, daß man ihn nicht ändern möchte, ein "const" um 
das zu dokumentieren nicht falsch ist.

Wenn ich das Päd. Wieder weggelegt hab, kann ich es ja mal testen.

: Bearbeitet durch User
Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Georg G. schrieb:
>> Dann probier es aus.
>>
>> char str0[] = "Hello World";
>
> Hängt damit zusammen, dass str0 hier global sichtbar ist und daher
> von anderen Modulen geändert werden könnte.
>
> Mach es mal „static“.

das hat damit nichts zu tun.
char str0[] = "Hello World";   /* 1 */
char *str1 = "Hello World";    /* 2 */
#define str2 "Hello World"     /* 3 */

gcc legt str0 (veränderbar) im .data Segment ab. Str1 und str2 (wenn 
benutzt) werden als Literale im .text (oder .rodata) Segment abgelegt 
und sind damit per Definition unveränderbar. Ein const braucht's dazu 
nicht.

: Bearbeitet durch User
Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg G. schrieb:
> Dann probier es aus.
>
> char str0[] = "Hello World";
> #define str1 "tralala"
> i = strlen(str1);

ok, ich bin von folgenden ausgegangen:
char str0[] = "Hello World";
i = strlen(str0);

oder
#define str1 "tralala"
char str0[] = str1
i = strlen(str0);

und das sollte immer das gleiche sein.

Autor: Carl D. (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
>
> char str0[] = "Hello World";   /* 1 */
> char *str1 = "Hello World";    /* 2 */
> #define str2 "Hello World"     /* 3 */
> 
>
> gcc legt str0 (veränderbar) im .data Segment ab. Str1 und str2 (wenn
> benutzt) werden als Literale im .text (oder .rodata) Segment abgelegt
> und sind damit per Definition unveränderbar. Ein const braucht's dazu
> nicht.

Nicht so ein AVR-GCC, denn der muß mit 2 separaten Adressräumen umgehen 
und legt Texte nur dann in FLASH ab, wenn man ihn dazu zwingt.

Autor: Andreas B. (andreas_b77)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> Nicht so ein AVR-GCC, denn der muß mit 2 separaten Adressräumen umgehen
> und legt Texte nur dann in FLASH ab, wenn man ihn dazu zwingt.

String-Literale sind in C nicht beschreibbar. Auch wenn das auf dem AVR 
möglich ist, ist das Verhalten undefiniert wenn man das auch macht.

Damit kann der Compiler davon ausgehen, dass ein als Literal gegebener 
String sich zur Laufzeit nicht verändert und entsprechend optimieren. 
Ein extra const braucht es dafür nicht.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas B. schrieb:
> String-Literale sind in C nicht beschreibbar. Auch wenn das auf dem AVR
> möglich ist, ist das Verhalten undefiniert wenn man das auch macht.

Früher gab's mal -fwritable-strings (wurde allerdings - 
vernünftigerweise - abgeschafft).

Autor: Carl D. (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas B. schrieb:
> Carl D. schrieb:
>> Nicht so ein AVR-GCC, denn der muß mit 2 separaten Adressräumen umgehen
>> und legt Texte nur dann in FLASH ab, wenn man ihn dazu zwingt.
>
> String-Literale sind in C nicht beschreibbar. Auch wenn das auf dem AVR
> möglich ist, ist das Verhalten undefiniert wenn man das auch macht.
>
> Damit kann der Compiler davon ausgehen, dass ein als Literal gegebener
> String sich zur Laufzeit nicht verändert und entsprechend optimieren.
> Ein extra const braucht es dafür nicht.

Ich habe nichts von der Beschreibbarkeit von String-Konstanten 
geschrieben, sondern von der Tatsache, daß ein AVR mehrere Adressräume 
hat. Der Compiler kann eine String-Konstante nicht einfach in den 
FLASH-Bereich stecken, den ein solcher String hat keine Adresse im 
Adress-Raum, in dem ein char str[10] liegt.
Strings sind im RAM-Adress-Raum, const char Flash[] = "Flash" steht im 
FLASH-Adress-Raum.
Beide beginnen bei 0, auch wenn im RAM-Adress-Raum bis 0x60/0x100 
erstmal Register/Io kommt.
Es gibt spezielle Befehle, um auf Konstanten im FLASH zuzugreifen

Was braucht's noch, um den Unterschied zu einem ARM mit 4GB linearem 
Adress-Raum zu verstehen?

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Georg G. schrieb:
>> Dann probier es aus.
>>
>> char str0[] = "Hello World";
>
> Hängt damit zusammen, dass str0 hier global sichtbar ist und daher
> von anderen Modulen geändert werden könnte.
>
> Mach es mal „static“.

Das ändert nichts, da str0 trotzdem hintenherum über Zeigerzugriffe
verändert werden könnte. Im vorliegenden Beispiel könnte der Compiler
diesen Fall zwar ausschließen, da das Programm nur aus einer einzigen
Funktion (main) besteht, in der keinerlei Zeigergewurschtel stattfindet.
In etwas kopmplexeren Programmen geht aber diese Sorte von Analyse um
zu viele Ecken und ist deswegen für den Compiler zu schwer.

Mit "const" sieht die Sache anders aus, da hiermit der Programmierer dem
Compiler zusichert, dass str0 nirgends im Programm geändert wird, auch
nicht über Zeigertricks.

Ebenfalls zur Compilezeit ausgewertet wird strlen in diesem Beispiel,
und das sogar ohne die Verwendung von "const":

int main(void) {
  char i;
  char str2[] = "Hello World";

  /*
  Hier kann beliebiger Code mit Ausnahme von
  - direkten Schreibzugriffen auf str2,
  - Schreibzugriffen über Zeiger und
  - Aufrufen externer Funktionen
  stehen.
  */

  i = strlen(str2);
  PORTA = i;

  return 0;
}

Hier kann der Compiler leicht sehen, dass zwischen der Definition von
str2 und dem strlen-Aufruf der String nicht verändert wird, so dass die
Optimierung angewendet kann.

Sobald aber anstelle des Kommentars eine Anweisung wie diese hier

  PORTA = 42;

steht, ist es vorbei mit der Optimierung, da die Zuweisung an PORTA ein
(etwas kaschierter) Zugriff über Zeiger ist, der (zumindest in den Augen
des Compilers) str2 überschreiben könnte. Deswegen wird hier strlen zur
Laufzeit und nicht zur Compilezeit ausgeführt.


Edit:

Macht man in diesem Beispiel str2 static, wird ebenfalls nicht mehr
optimiert. Das sich da Ganze in der main-Funktion abspielt, besteht
eigentlich keine Gefahr, dass str2 irgendwo überschreiben wird. Jedoch
behandelt GCC main wie jede andere C-Funktion. Und würde die Funktion im
Beispiel nicht main, sondern func heißen, könnte es tatsächlich sein,
dass vor dem Aufruf von func ein Stück Code ausgeführt wird, der über
abenteuerliche Zeigeroperationen str2 verändert.

: Bearbeitet durch Moderator
Autor: Hans-Georg L. (h-g-l)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg G. schrieb:
>
> sizeof() liefert die gesamte Länge, strlen() liefert die Länge bis zur
> ersten 0x00. Woher soll das Programm zur Laufzeit auch wissen, dass der
> Programmierer da höheren Schwachsinn geschrieben hat.

Es ist durchaus in C üblich auf diese Weise stringlisten zu definieren.

Beispiel:
int main()
{
  char *list =  "text_1\0" \
      "text_2\0" \
      "text_3\0" \
      "text_4\0" \
      "\0";

  for (char*p = list; *p != 0; p += strlen(p) + 1)
  {
    printf("%s\r\n", p);    
  }
}

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hans-Georg L. schrieb:
> Es ist durchaus in C üblich auf diese Weise stringlisten zu definieren.

wer macht so etwas wenn es Array gibt?

[c]
int main()
{
  char *list[] =  { "text_1", "text_2", "text_3", "text_4", 0 };

  int i = 0;
  while( list[i] != 0 )
  {
    printf("%s\r\n", list[i] );
  }
}

Autor: Daniel A. (daniel-a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> Hans-Georg L. schrieb:
>> Es ist durchaus in C üblich auf diese Weise stringlisten zu definieren.
>
> wer macht so etwas wenn es Array gibt?

Microsoft, natürlich! Beispiel: 
https://msdn.microsoft.com/en-us/library/ms683187(...

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter II schrieb:
> Hans-Georg L. schrieb:
>> Es ist durchaus in C üblich auf diese Weise stringlisten zu definieren.
>
> wer macht so etwas wenn es Array gibt?
>
> [c]
> int main()
> {
>   char *list[] =  { "text_1", "text_2", "text_3", "text_4", 0 };
>
>   int i = 0;
>   while( list[i] != 0 )
>   {
>     printf("%s\r\n", list[i] );
>   }
> }

Das ist was Anderes: ein Zeigerarray auf Stringliterale. Belegt für 
jeden der Texte nochmal einen Pointer. Bei deinem Beispiel und 32 
Bit-Zeigern also mal eben so rund 70% Overhead.
Kann man so machen (ich mach's - meist - auch so), aber wenn's eng wird, 
nicht unbedingt besser ...

Autor: Jörg W. (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel A. schrieb:
> Peter II schrieb:
>> Hans-Georg L. schrieb:
>>> Es ist durchaus in C üblich auf diese Weise stringlisten zu definieren.
>>
>> wer macht so etwas wenn es Array gibt?
>
> Microsoft, natürlich! Beispiel:
> https://msdn.microsoft.com/en-us/library/ms683187(...

Environment-Variablen haben ja nun nichts in erster Linie mit
Microsoft zu tun.

Dass man diese erstmal nur linear im Speicher anordnen kann, ist
völlig logisch, denn sie kommen ja eben daher, was ihr Name sagt:
aus der Umgebung (des aufgerufenen Prozesses).  Dort liegen sie
einfach nur hintereinander in einem Stück Speicher.

Unter Unix baut der Startup-Code dann dafür noch ein Pointer-Array
(im Stack) auf, welches als dritter Parameter an main() übergeben
wird.  Dass die eigentlichen Strings im Speicher hintereinander liegen,
kann man sich aber im Debugger ansehen:
(gdb) p environ
$6 = (char **) 0x7fffffffe528
(gdb) p *environ
$7 = 0x7fffffffe823 "COLUMNS=151"
(gdb) p *(char *)0x7fffffffe823@100
$8 = "COLUMNS=151\000LINES=46\000XTERM_SHELL=/bin/tcsh\000TERMCAP=xterm|X11 terminal emulator:@7=\\EOF:@8=\\EOM:F1=\\E"

Markus F. schrieb:
> Kann man so machen (ich mach's - meist - auch so), aber wenn's eng wird,
> nicht unbedingt besser ...

Ist halt der übliche space/time tradeoff: ohne diese Zeiger musst
du jedesmal durch alles durchtippeln.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Edit:
>
> Macht man in diesem Beispiel str2 static, wird ebenfalls nicht mehr
> optimiert. Das sich da Ganze in der main-Funktion abspielt, besteht
> eigentlich keine Gefahr, dass str2 irgendwo überschreiben wird. Jedoch
> behandelt GCC main wie jede andere C-Funktion. Und würde die Funktion im
> Beispiel nicht main, sondern func heißen, könnte es tatsächlich sein,
> dass vor dem Aufruf von func ein Stück Code ausgeführt wird, der über
> abenteuerliche Zeigeroperationen str2 verändert.

Diese abenteuerlichen Zeigeroperationen rufen aber in C undefiniertes 
Verhalten hervor, somit darf ja Mist rauskommen, wenn str2 verändert 
wurde. Der Compiler muss das also eigentlich nicht berücksichtigen.

Jörg W. schrieb:
>>> wer macht so etwas wenn es Array gibt?
>>
>> Microsoft, natürlich! Beispiel:
>> https://msdn.microsoft.com/en-us/library/ms683187(...
>
> Environment-Variablen haben ja nun nichts in erster Linie mit
> Microsoft zu tun.

Nein, aber dass es um Environment-Variablen geht, ist ja hier nicht das 
Problem, sondern die Art, wie die API-Funktion sie zurückgibt. Und die 
ist auf Microsofts Mist gewachsen.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Diese abenteuerlichen Zeigeroperationen rufen aber in C undefiniertes
> Verhalten hervor

Nicht unbedingt. Wenn die Funktion einen Zeiger auf die als static
deklarierte lokale Variable (bspw. über den Rückgabewert) anderen
Programmteilen zu Verfügung stellt, dürfen diese damit die Variable ganz
legal verändern. Beim nächsten Aufruf der Funktion steht dann in der
Variable etwas anderes, obwohl sie lokal ist.

Ok, in diesem Fall ist es die Funktion selbst, die die Adresse ihrer
lokalen Variable anderen Programmteilen preisgibt. Der Compiler könnte
die Optimierung also auf diejenigen Fälle beschränken, wo er sicher sein
kann, dass der Array-Zeiger nicht nach außen gelangt. Dazu müsste er nur
die Funktion selbst (und keine externen Programmteile) analysieren, was
ja prinzipiell machbar sein sollte, da die dafür benötigten Algorithmen
zur Datenflussanalyse sowieso schon existieren.

Autor: Jochen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow! Was für eine Diskussion!
Für mich gilt: Verwende" strlen", auch wenn es länger dauert.

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Rolf M. schrieb:
>> Diese abenteuerlichen Zeigeroperationen rufen aber in C undefiniertes
>> Verhalten hervor
>
> Nicht unbedingt. Wenn die Funktion einen Zeiger auf die als static
> deklarierte lokale Variable (bspw. über den Rückgabewert) anderen
> Programmteilen zu Verfügung stellt, dürfen diese damit die Variable ganz
> legal verändern.

Klar, aber das ist nicht das, was ich unter "abenteuerliche 
Zeigeroperationen" verstehe.

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.