Forum: Mikrocontroller und Digitale Elektronik C-Funktion- Übergabe char vers. constant char


von Dietmar S. (dsausw)


Lesenswert?

Hallo,
ich habe gerade in meinen K&R hineingebissen, wg.
folgendem Problem:

MSP430- CCS 6.0 - TI - c-compiler
Democode vom Distri weiterverbastelt:

Für ein GLCD wird eine Laufschrift angezeigt (funktioniert!)
Es gibt Texte, die einfach im Quellcode mitgegeben werden
und es gibt constant-Texte im Flash (das soll einmal ein Menue werden).
1
const char text[] = "Das ist ein wenig Text im Flash";
Teil der Lauftext-Funktion:
1
void scroll_left(const char *string,unsigned char zeile,unsigned char size,unsigned char wdh,unsigned char pause)
2
{
3
  unsigned char i,j,space;
4
  char x;                   // siehe unten bei warning
5
  unsigned char buffer[128];
6
7
  for (j=0;j<128;j++)buffer[j]=0;
8
  x = strlength(string);
9
10
  ......// DA kommt nur noch bit-Geschubbse
11
}
Von main kommt, z.B.
1
scroll_left(text, 2, 2, 2, 10); // text aus dem Flash - s.o.
und strlength:
1
char strlength(char  *string)
2
{
3
  char *p = string;
4
  while(*p != (0x00)){p++;};
5
6
  return p - string;
7
}
Problem = 2 Warnungen:
Der compiler meckert natürlich an, das das 'constant char'
von *string nicht dem Wert '*string' für strlength entspricht.

#169-D argument of type "const char *" is incompatible with parameter of 
type "char *"

und meint dann zu dem 'x'
#552-D variable "x" was set but never used
Wie gesagt, es funktioniert trotzdem (auch der Rückgabewert passt)!!??
Da ich aber keine Warnungen mag und auch ganz gerne verstehe, was da 
passiert:
Wenn ich in der Funktion 'strlength' sowohl Daten aus dem Flash,
als auch aus dem RAM verarbeiten möchte, kann man das in einer Funktion?

Besten Dank!
Dietmar

von Karl H. (kbuchegg)


Lesenswert?

Da die MSP eine von Neumann Architektur haben, düfte es eigentlich 
keinen Unterschied machen, ob der COmpiler die Texte ins Flash oder ins 
RAM legt. In beiden Fällen sind die Zugriffe (wegen van Neumann) gleich.


Zu deiner Frage.

Ein const in einer Argumentliste einer Funktion kann gelesen werden als 
die Zusicherung der Funktion, den WErt nicht zu verändern. D.h. die 
Funktion gibt damit an den Aufrufer eine Garantie
1
void foo( const char* arg )
2
{
3
...
4
}

ist also die Zusicherung der Funktion, dass sie nicht versuchen wird, 
die char auf die der Pointer zeigt zu verändern. Wenn im Code das 
trotzdem versucht wird
1
void foo( const char* arg )
2
{
3
  *arg = 'a';
4
}
dann fliegt dem Programmierer dieser Funktion eine Fehlermeldung um die 
Ohren. Denn dann hält sich der Code nicht an diese Zusicherung.

Warum ist das wichtig.
Nun. Wenn der Aufrufer einen Text hat, so wie hier
1
const char txt[] = "Hallo";
2
3
 foo( txt );
dann muss er sich darauf verlassen können, dass nach Rückkeehr von der 
Funktion der Text immer noch so ist, wie er vorher war. SChliesslich hat 
er ihn ja auch deshalb als 'const' markiert, damit ihn der Compiler 
daran hindert, den Text zu verändern. Was für ihn gilt, muss daher auch 
für die Funktion gelten: die Funktion muss die Zusicherung abgeben, 
nicht zu versuchen den Text zu ändern. Genau das macht sie aber mit dem 
const in
1
void foo( const char* arg );

Es gibt noch einen anderen Fall
1
...
2
   foo( "text" );

String Literale sind per Definition unveränderbar. D.h. auch hier muss 
die Funktion diese Zusicherung abgeben.

von stefanus (Gast)


Lesenswert?

Ist logisch. strlength() hat nicht das const Schlüsselwort. Der Compiler 
geht daher davon aus, dass strlength() die variable eventuell verändert. 
Ob sie es das wirklich macht, ist derm Compiler egal, das prüft er 
nicht.

scroll_left() hat das const Schlüsselwort. Sie verspricht dem Compiler, 
dass die Variable nicht verändert wird. Aber sie ruft strlength() auf, 
welche das nicht mehr verspricht. Diesen Konflikt meldet der Compiler 
als Warnung.

Wenn du der Variable x nur einen Wert zuweist, den aber nirgends 
verwendest (ausliest), dann ist die Warnung völlig korrekt. Je nach 
Optimizer Einstellung fürht dies dazu, dass die Variable x im Binärcode 
gar nicht existiert. Leider hast Du den wirklich wichtigen Part des 
Quelltextes ausgelassen.

von Dietmar S. (dsausw)


Lesenswert?

Besten Dank, die Herren!

@Karl Heinz:
Das war mir klar und es findet sich im Sinn auch
im K&R und im 'C von A bis Z'- was immer man auch davon halten mag.
Aber schön erklärt, wie immer.

@stefanus:
o.k.- was willst Du wissen ?? kleiner Scherz.
'x' taucht wirklich nicht mehr auf in 'scroll_left'.
Da hat der compiler Recht.
Nur- der Rückgabewert stimmt trotzdem !!??
Ich habe extra die Texte variiert, damit das kein Zufall
beim Debuggen ist.

Meine Frage war, wie ich strlength() dazu bekomme (evtl.),
char* und constant char* zu verarbeiten.

von Karl H. (kbuchegg)


Lesenswert?

Dietmar Sch. schrieb:

> @Karl Heinz:
> Das war mir klar und es findet sich im Sinn auch
...

> Meine Frage war, wie ich strlength() dazu bekomme (evtl.),
> char* und constant char* zu verarbeiten.

Jetzt muss ich mich aber wundern
Welchen Teil der Ausführungen hast du nicht verstanden, warum du in
1
void scroll_left(const char *string,unsigned char zeile,unsigned char size,unsigned char wdh,unsigned char pause)
2
{
3
  unsigned char i,j,space;
4
  char x;                   // siehe unten bei warning
5
  unsigned char buffer[128];
6
7
  for (j=0;j<128;j++)buffer[j]=0;
8
  x = strlength(string);
9
...
eine const Warnung kriegst? Wenn scroll_left an seinen Aufrufer die 
Zusicherung const char* macht, dann kann es nicht FUnktionen aufrufen, 
die potentiell in der Lage wären (wegen der fehlenden const Zusicherung) 
die Zeichen zu verändern.

Und noch viel schlimmer: Welchen Teil hast du nichtg verstanden, warum 
eine Modifikation der Funktion strlength auf
1
char strlength(const char  *string)
2
/*             *****                */
3
{
4
  char *p = string;
5
  while(*p != (0x00)){p++;};
6
7
  return p - string;
8
}
die 1. Warnung beseitigen würde?


Zur 2. Warnung sag ich mal nichts weiter. Die wird dir doch nicht 
wirklich ein "Problem" bereiten.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Dietmar Sch. schrieb:
> Meine Frage war, wie ich strlength() dazu bekomme (evtl.),
> char* und constant char* zu verarbeiten.

Indem Du es mit einem const-Pointer deklarierst.

Einer Funktion, die const char* erwartet, darf man auch char* übergeben.

Andersrum darf ein const char* nicht an eine Funktion übergeben werden, 
die char* erwartet.


Wo liegt der Reiz, eine eigene Stringlängenfunktion zu schreiben? Warum 
verwendest Du nicht einfach strlen?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Wo liegt der Reiz, eine eigene Stringlängenfunktion zu schreiben? Warum
> verwendest Du nicht einfach strlen?

... die – ganz nebenbei bemerkt – ein "const" in ihrer Deklaration
stehen hat
1
size_t strlen(const char *s);

und trotzdem ohne Warnungen auch für Nicht-Const-Strings anwendbar ist
;-)

von Karl H. (kbuchegg)


Lesenswert?

Rufus Τ. Firefly schrieb:

> Einer Funktion, die const char* erwartet, darf man auch char* übergeben.

Wenn ich da anhängen darf. Vielleicht hat er ja den Teil nicht 
verstanden.

Genau deshalb bin ich ja auf der "Zusicherung" so rumgeritten!

Wenn ich 2 Bücher habe, eine original Gutenberg-Bibel und "Die kleine 
Raupe Nimmersatt", dann kannst du die dir bei mir ausleihen.#

Gibst du mit die Zusicherung nichts in die Bücher hineinzuschreiben, 
dann kannst du von mir sowohl die Gutenberg-Bibel haben als auch die 
Raupe Nimmersatt. Persönlich wär mir das egal, ob du etwas in die "Raupe 
Nimmersatt" hineinschreibst oder nicht, aber wenn du mir zusicherst, das 
nicht zu tun, ist es auch gut. Selbst dann, wenn ich in dem Fall nicht 
auf dieser Zusicherung bestehe.
Aber bei der Gutenberg Bibel ist mir das nicht egal. Da WILL ich von dir 
diese Zusicherung haben.

Gibst du mir die Zusicherung nicht, dann kriegst du von mir nur die 
Raupe Nimmersatt. Gibst du mir aber die Zusicherung, dann kannst du 
beides von mir haben.

: Bearbeitet durch User
von Dietmar S. (dsausw)


Lesenswert?

PAH! - wenn K&R das dürfen (section 5.4 page 103),
dann darf ich das auch!
;-)
Ne- das war so vorgegeben, vom Beispielcode, wie
eingangs erwähnt.
@Karl Heinz:
Ganz einfach ein Brett vor dem Kopf! Und dann noch ein altes.

Rufus hat es gelockert:
>Einer Funktion, die const char* erwartet, darf man auch char* übergeben.

Geändert-läuft PROBLEM SOLVED!

Besten Dank und Schönen Feierabend!

von Dietmar S. (dsausw)


Lesenswert?

Ich würde nie in irgendeinem geliehenen Buch herumkritzeln!
Von daher 'immer' const char*'.
;-)

von Karl H. (kbuchegg)


Lesenswert?

Dietmar Sch. schrieb:
> Ich würde nie in irgendeinem geliehenen Buch herumkritzeln!
> Von daher 'immer' const char*'.
> ;-)

Jetzt verstehen wir uns.
:-)

Ein 'const char*' sollte daher in einer Funktions-Argumentliste 
eigentlich der Normalfall sein. Und nur dann, wenn die Funktion 
tatsächlich den Text ändern muss, dann und nur dann kommt das const weg.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Karl Heinz schrieb:
> Wenn ich 2 Bücher habe, eine original Gutenberg-Bibel und "Die kleine
> Raupe Nimmersatt"

Damit wäre auch geklärt, mit welchen Büchern du so gut programmieren
gelernt hast und wie dein Tipp an jeden Programmieranfänger "Kauf dir
ein Buch!" zu verstehen ist ;-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Welches andere Buch hat denn auch so ein schönes Loch?

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.