www.mikrocontroller.net

Forum: Compiler & IDEs 'char* str' oder 'char *str'


Autor: Steve (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Liebe Leute,
ist es sinnvoller, die Deklaration eines Pointers, der nach der 
Zuweisung durch malloc eine Zeichenkette aufnimmt, als 'char* str' oder 
'char *str' zu schreiben?
Korrekt ist beides, aber was ist praktischer und effizienter
a) als globale Variable
b) lokal am Anfang einer Funktion
c) lokal inmitten einer Funktion
d) als Argument einer Funktion
e) wenn eine Folge von Pointern definiert wird?

Steve

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst auch 'char*str' oder 'char * str' schreiben, es macht 
überhaupt keinen Unterschied.

C braucht Leerzeichen nur dort, wo Wörter getrennt werden müssen, 
Operatoren werden immer erkannt.


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu Deiner 2. Frage, in der Regel ist es effizienter, eine Variable erst 
unmittelbar vor der Verwendung zu deklarieren, also c).


Peter

Autor: Steve (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Du kannst auch 'char*str' oder 'char * str' schreiben, es macht
>überhaupt keinen Unterschied.

Das stimmt so nicht. Als argument list mag das hinkommen.
>void fun(char* s1, char* s2) und
>void fun(char *s1, char *s2) ist syntaktisch ähnlich und kann sich höchstens im 
Maschinencode unterscheiden.

ABER:
Bei einer Variablenliste kann ich nur mit der 2. Schreibweise
>char *s1,*s2,*s3;
einen zusammenhängenden Speierbereich erzwingen.
Schreibe ich
>char* s1,s2,s3;
sind s2 und s3 keine Pointer. Schreibe ich
>char* s1;
>char* s2;
>char* s3;
könnten diese Pointer infolge des Alignments an unzusammenhängenden 
Adressen landen.

Noch komplizierter wird es, wenn die Pointer gleichzeitig initialisiert 
werden (z.B. 'char* s=(char*)malloc(10)'). Hier gehört der '*' im 
'(char*)malloc(19)' ja eindeutig zum char, so dass es Sinn macht, diese 
Schreibweise im 'char* s' zu wiederholen.

Wie ich schrieb, kann beides in den einfachen Fällen korrekt sein. Aber 
angesehen von Peters Pauschalisierung, daß Leerzeichen nur Wörter 
trennen: wer kennt sich mit diesem Problem wirklich aus und kann 
Argumente für oder gegen die verschiedenen Möglichkeiten liefern?

Steve

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steve wrote:

>>char *s1,*s2,*s3;
>>char* s1,s2,s3;

Nun, diese beiden Zeilen unterscheiden sich durch mehr als die Anzahl 
der Leerzeichen, sind also daher auch nicht identisch.

Du must schon richtig lesen, was ich schrieb.

Aber:
char *s1,*s2,*s3;
und:
char
*
s1
,
*
s2
,
*
s3
;
sind identisch.


Peter

Autor: Steve (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, Peter, aber ich möchte hier keine Korinthen kacken, sondern suche 
eine einfache Antwort auf eine relativ einfache Frage. Ich gebe dir 
vollkommen recht, hoffe aber trotzdem noch auf sinnvollere Antworten von 
anderen.

Danke für dein Verständnis
Steve

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steve wrote:
> Ja, Peter, aber ich möchte hier keine Korinthen kacken

Das ist kein "Korinthen kacken" sondern der Versuch, Dir begreiflich zu 
machen, daß man erstmal zwischen Syntaxregeln und Ausdrücken 
abstrahieren muß.

Wenn Du eine explizite Bindung des '*' zu einem Ausdruck haben willst, 
mußt ihn klammern, Leerzeichen bringen weniger als ein Mückenfurz.

Mach Dir nichts draus, ich habs auch lange nicht kapiert.

Besonders mit #defines haben selbst gestandene C-Profis so ihre 
Probleme. Man muß erst im Kopf kapieren, daß es nur ne Textersetzung 
ist.


Peter

Autor: Lukas R. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steve, es ist so wie du sagst:
Vorzugsweise sollten Variablen, auf die vom Programm in direkter Abfolge 
zugegriffen wird (so daß zwischendurch kein cache miss eintritt), in 
einer Zeile deklariert werden. Von der Syntax her hat Peter zwar recht, 
aber die Referenzhandbücher der mir bekannten C- und C++-Compiler weisen 
expizit darauf hin, daß nur so zufriedenstellende Optimierung möglich 
ist.

Also:
char*s1=(char*)malloc(n1),*s2=(char*)malloc(n2),...;
ob nun mit oder ohne Zuweisung, das tut sich nichts. Vor (nicht hinter!) 
dem '*' kannst du der Übersichtlichkeit halber ein Leerzeichen einfügen, 
aber nur konsistent, sonst leidet wieder die Optimierung.

Lukas

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lukas R. wrote:

> Vorzugsweise sollten Variablen, auf die vom Programm in direkter Abfolge
> zugegriffen wird (so daß zwischendurch kein cache miss eintritt)

Wobei sich erstmal die Frage stellt, welcher MC hat den überhaupt einen 
Cache.

Hier im GCC-Forum sind doch hauptsächlich AVR, MSP und ARM7 unterwegs 
(8086 sind ja im PC-Forum besser aufgehoben).


Malloc würde ich aufm AVR sowieso nur mit ner Kneifzange anfassen.
Entweder ich weiß, daß mein AVR den benötigten Speicher für die 
Applikation hat (worst case) oder ich nem gleich was größeres.
Ehe ich da noch ne Ausnahmebehandlung fürs malloc einbaue, laß ich mir 
lieber ein Bein abhacken. Ein Kunde mit einem Gerät, welches 
malloc-Fehler meldet würde mich ja damit totschlagen.


Peter

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hier im GCC-Forum sind doch hauptsächlich AVR, MSP und ARM7 unterwegs
>(8086 sind ja im PC-Forum besser aufgehoben).
Da hast du dich aber gerade noch aus der Scheiße gezogen...

>Malloc würde ich aufm AVR sowieso nur mit ner Kneifzange anfassen.
Und schon steckst du wieder drin.

gcc ist erst mal ein gängiger C-Compiler für diverse Plattformen, von 
denen AVRs eindeutig die Minderheit darstellen, und wenn Steve malloc 
verwendet, solltest du davon ausgehen, daß es eben nicht um AVRs geht. 
(In dieser Situation ist es natürlich ausnahmsweise gerechtfertigt, DOCH 
einen AVR anzunehmen, da nur so noch das arme Danegger-Ego gerettet 
werden kann.)

Steve, solange du den Peter immer schön bestätigst, vermeidest du zwar 
weitere "Ich hab das schon immer so gemacht"-Antworten, du solltest aber 
doch insgeheim Lukas glauben, der es auf den Punkt gebracht hat 
(gcc-Manual, Kapitel Optimierung, Abschnitt Verschiedenes).

Autor: Karl vom Kanal (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Malloc würde ich aufm AVR sowieso nur mit ner Kneifzange anfassen.
>Entweder ich weiß, daß mein AVR den benötigten Speicher für die
>Applikation hat (worst case)

Würde ich so nicht sagen. malloc() ist insofern flexibler, als daß man 
den freien Speicher effektiver nutzen kann und vorher testen kann, ob 
der Platz im RAM noch reicht. Lokale arrays werden immer angelegt, egal 
der der Stack anschließend ins Nirwana geht.
Wenn man eine ATmega2561 mit 8K Ram hat, wird man schlecht auf etwas 
Größeres ausweichen können.

Aber
> 'char* s=(char*)malloc(10)').
bringt garnichts, außer ein free() notwendig zu machen. char s[10] ist 
effizienter.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steve wrote:

> Bei einer Variablenliste kann ich nur mit der 2. Schreibweise
>>char *s1,*s2,*s3;
> einen zusammenhängenden Speierbereich erzwingen.
> Schreibe ich
>>char* s1,s2,s3;
> sind s2 und s3 keine Pointer. Schreibe ich
>>char* s1;
>>char* s2;
>>char* s3;
> könnten diese Pointer infolge des Alignments an unzusammenhängenden
> Adressen landen.

Quark.  Das können sie so oder so (und das völlig unabhängig vom
Alignment, also auch auf Architekturen wie dem AVR, die keinerlei
Alignment-Restriktionen besitzen).  Keiner garantiert dir, dass die
Zeigervariablen an aufeinanderfolgenden oder anderweitig
zusammenhängenden Adressen landen, ja nichtmal, dass sie denn
überhaupt jemals den RAM sehen.  Sie können genauso gut in einem
Register(paar) landen oder aber vom Compiler als vollständig unnütz
angesehen und im Maschinencode eliminiert werden (obwohl sie dem
Programmierer zum Formulieren seiner Problemlösung sehr nützlich
waren).

Es ist also völlig schnuppe, ob du
char *s1, *s2, *s3;

oder
char *s1;
char *s2;
char *s3;

schreibst.  Allerdings wird daraus auch offensichtlich, dass die
Schreibweise
char* s1;
ein Problem bekommt, sobald man daraus
char* s1,* s2,* s3;
machen will.  Sieht dann ziemlich seltsam aus.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja,

was der Jörg schreibt, das gefällt mir immer wieder, das hat Hand und 
Fuß.

Ich hab das auch schon erlebt, daß Compiler einen Eigensinn an den Tag 
legen, was die Variablendeklaration betrifft.

Z.B. kann es passieren, daß er nur dann eine Variable in einem Register 
anlegt, wenn sie häufig genug benutzt wird.
Ich hab mal in nem Code eine Optimierung vorgenommen, die einen Zugriff 
einsparte und schon war der Code größer und langsamer.

Wenn also s2 häufig benutzt wird, kann s2 in einem Register landen und 
s1, s3 im SRAM. Nichts ist es mit der Reihenfolge im Quelltext.


Peter

Autor: Bernhard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallole,
die ursprüngliche Frage lautete:
...
ist es sinnvoller, die Deklaration eines Pointers, der nach der
Zuweisung durch malloc eine Zeichenkette aufnimmt, als 'char* str' oder
'char *str' zu schreiben?
...

Dem Compiler ist beides - haben ja schon viele erwähnt - reichlich 
"schnuppe".

Entscheidend ist meiner Meinung nach, auf welche Weise der Code am 
lesbarsten wird. Und dafür gibt es Regeln, die man z.B. im Duden findet 
- nicht lachen, auch ein C-Programm ist in erster Linie ein 
geschriebener Text, also etwas, was gelesen wird!

Im Duden läßt sich folgendes finden:
Die Satzzeichen Punkt, Komma, Semikolon, Doppelpunkt folgen direkt ohne 
Leerzeichen auf das vorangehende Wort; hinter ihnen läßt man ein 
Leerzeichen.
Vor einer sich öffnenden Klammer kommt ein Leerzeichen, genau wie hinter 
einer schließenden Klammer.
Hinter einer sich öffnenden Klammer kommt Kein Leerzeichen, genau wie 
vor einer schließenden Klammer.
Vor und hinter mathematischen Zeichen ( + - * / ...) kommt ein 
Leerzeichen.

Damit ist für mich klar:
Es sollte 'char * str' heißen, nicht 'char* str' und auch nicht 'char 
*str'.

Grüße
Bernhard

Autor: ikletti (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zitat:
"Es sollte 'char * str' heißen, nicht 'char* str' und auch nicht 'char 
*str'."

Ja, aber: Wie Du schon sagst, sollte der Text gelesen werden. Und in 
diesem Fall scheint die Variante 'char *str' die wenigsten Probleme beim 
Verstehen verursachen, da eindeutig ist wo der Stern hingehört und wozu 
er gut ist.

Wenn man Quellcode aufmerksam liest und ein gewisses Grundverständnis 
mitbringt (um vom Syntax-Highlighting erst gar nicht zu sprechen) kann 
man es nicht verwechseln, aber im Prinzip könnte man sonst 'char * str' 
auch für eine Multiplikation halten.

Autor: Bernhard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Wenn man Quellcode aufmerksam liest" - ich lese im Allgemeinen mehr 
husch-husch und überlese auf diese Weise gerne den 'rangepeppten' Stern. 
Und das mit der Multiplikation ist doch wohl etwas weit hergeholt.

Jedenfalls spricht m.E. nichts dagegen, die allgemeinen 
Rechtschreibregeln einzuhalten.

Grüße
Bernhard

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wer diese zauberhafte Deklarationsmimik von C übersichtlicher halten 
will, der macht es so:
  typedef char *char_ptr;
und dann
  char_ptr s1, s2, s3;

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ja, aber: Wie Du schon sagst, sollte der Text gelesen werden. Und in
> diesem Fall scheint die Variante 'char *str' die wenigsten Probleme
> beim Verstehen verursachen, da eindeutig ist wo der Stern hingehört und
> wozu er gut ist.

Genau das finde ich nicht. Das '*' ist Teil des Typs, deshalb gehört es 
meines Erachtens zum Rest des Typs, also 'char* str'.


> Wer diese zauberhafte Deklarationsmimik von C übersichtlicher halten
> will, der macht es so:
>   typedef char *char_ptr;

Zeiger hinter Typedefs verstecken würde ich auf gar keinen Fall.

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kernighan und Ritchie (C, ANSI C) verwenden in ihrem Buch die
Schreibweise

  char *str;

was folgendermaßen zu lesen ist:

  *str, also der dereferenzierte Zeiger str, ist vom Typ char.

Da der Dereferenzierungsoperator * üblicherweise direkt vor die
Variable geschrieben wird (z.B. in c = *str), ist es konsequent, dies
auch in Definitionen zu tun.

Die Schreibweise

  char* str;

hingegen wurde von Stroustrup (C++) populär gemacht. Dass der Stern
aber zur Variable und nicht zum Typ gehört, zeigt die schon erwähnte
Problematik bei Mehrfachdefinitionen. Auch bei der Definition von
Funktionspointern wird dies deutlich:

  int (*fptr)(int);

bedeutet:

  *fptr, also der dereferenzierte Zeiger fptr, ist eine Funktion mit
  Integer-Argument und Integer-Rückgabewert.

Die entsprechende Stroustrup-Schreibweise wäre

  int(*)(int) f;

ist aber syntaktisch falsch.

Deswegen bevorzuge ich die K&R-Schreibweise, auch wenn diese bei
Definitionen mit Initialisierung etwas seltsam aussieht.

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.