Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Compilerwarnung Pointertyp const char **

5 views
Skip to first unread message

Lars Meier

unread,
Oct 18, 2009, 10:39:28 AM10/18/09
to
Hallo NG,

seit einiger Zeit schon habe ich ein Verständnisproblem im Zusammenhang
mit const und Zeigern: Häufig schreibe ich Code zum Parsen von speziell
formatiertem Text. Dabei gibt es bestimmte Textblöcke die an mehreren
Stellen eingelesen werden. Deshalb werden diese Blöcke meist von einer
eigenen Funktion bearbeitet. Diese Funktionen erhalten dann meist die
aktuelle Leseposition im String als "char **", so dass diese die
Leseposition weitersetzen können. Dabei soll der Text nicht veränderlich
sein, ich würde also gerne den Parameter ein const verpassen. Doch wo
muss es stehen? Ich hätte eigentlich gedacht "const char **" wäre
richtig. Doch dann meckert der Compiler. Hier ein Beispiel:

void func1(const char *s)
{
}

void func2(const char **s)
{
++(*s);
}


int main()
{
char buffer[100];
char *s = 0;

s = &buffer[10];
func1(s); // alles Bestens
func2(&s); // hier ist laut Compiler der Zeigertyp inkompatibel
return 0;
}

Der gcc sagt dazu:

cp.c:18: warning: passing argument 1 of ‘func2’ from incompatible
pointer type

Wie muss der Code richtig aussehen?

Lars

Alexander Bartolich

unread,
Oct 18, 2009, 12:31:03 PM10/18/09
to
Lars Meier schrieb:
> [...] Dabei soll der Text nicht verᅵnderlich
> sein, ich wᅵrde also gerne den Parameter ein const verpassen. Doch wo
> muss es stehen? Ich hᅵtte eigentlich gedacht "const char **" wᅵre
> richtig.

Das Schlᅵsselwort "const" bezieht sich auf den links davor stehenden
Ausdruck, auᅵer es steht nichts links davor, dann bezieht es sich auf
den rechts folgenden Ausdruck.

ᅵconst char **ᅵ ist also die Sonderform von ᅵchar const **ᅵ und gibt
an, dass der ᅵcharᅵ unverᅵnderlich ist.

> [...]


> void func2(const char **s)
> {
> ++(*s);
> }

Diese Funktion verᅵndert einen Zeiger vom Typ ᅵchar const*ᅵ, der an
der Adresse ᅵ*sᅵ liegt.

> int main()
> {
> char buffer[100];
> char *s = 0;
>
> s = &buffer[10];
> func1(s); // alles Bestens
> func2(&s); // hier ist laut Compiler der Zeigertyp inkompatibel
> return 0;
> }

Du ᅵbergibst ᅵfunc2ᅵ allerdings die Adresse eines Zeigers vom Typ
ᅵchar*ᅵ. Das ist nicht gestattet. Das Motiv hinter dieser Einschrᅵnk-
ung ist vermutlich, Systeme zu ermᅵglichen, die unterschiedliche Bit-
muster fᅵr const-Zeiger und non-const-Zeiger verwenden.

> Wie muss der Code richtig aussehen?

Rein grundsᅵtzlich ist deine Logik fragwᅵrdig.
Wenn man den Code so abᅵndert:

const char* t = s;
func2(&t);
s = t;

bleibt immer noch ᅵwarning: assignment discards qualifiers from pointer
target typeᅵ ᅵbrig. Verfolgt man den Ansatz konsequent weiter, wird
daraus:

const char* func2(const char *s)
{
return ++s;
}
[...]
s = func2(s);

--

Michael Schumacher

unread,
Oct 18, 2009, 4:31:48 PM10/18/09
to
Lars Meier wrote:

Wieso richtig? Er ist ja nicht flasch, bloß weil der Compiler eine
Warnung generiert hat (obwohl man die durchaus ernstnehmen sollte!).
Deklariere in main() "const char *s;" oder verwende dort den Aufruf
"func2 ((const char **) &s);" -- und der Compiler bleibt sprachlos.

Warum genau sich "const" und "nicht-const" nicht vertragen, kann Dir
Claus sicher in kapitelnumerierter Form aus der Bibel zitieren. ;-)


mike

Lars Meier

unread,
Oct 19, 2009, 2:05:38 PM10/19/09
to
Alexander Bartolich schrieb:

Schade, das ist ja eher unpraktisch. Ich hatte const bisher eher als
"Programmierhilfe" verstanden, die auf das Programm keinen Einfluᅵ hat.

>
>> Wie muss der Code richtig aussehen?
>
> Rein grundsᅵtzlich ist deine Logik fragwᅵrdig.

In wiefern fragwᅵrdig?

> Wenn man den Code so abᅵndert:
>
> const char* t = s;
> func2(&t);
> s = t;
>

Mit zwei Zeigern zu hantieren finde nicht gerade ᅵbersichtlich. Den
RW-Zeiger brauche ich nᅵmlich manchmal schon.

> bleibt immer noch ᅵwarning: assignment discards qualifiers from pointer
> target typeᅵ ᅵbrig. Verfolgt man den Ansatz konsequent weiter, wird
> daraus:
>
> const char* func2(const char *s)
> {
> return ++s;
> }
> [...]
> s = func2(s);
>

Genau das mᅵchte ich aber nicht, weil meine Funktionen in der Regel eine
Information ᅵber den Erfolg zurᅵckgeben und das soll auch so bleiben,
weil ich das ᅵbersichtlicher finde. Hinzu kommt, dass ich dann
unweigerlich bei der Zuweisung die schon erwᅵhnte Warning bekomme. Die
kann ich zwar auch "Wegcasten" aber, wenn ich mir letzlich doch alles
zurechtcasten muss, dann kann ichs mit dem const auch ganz lassen.

Ich denke, genau das werde ich jetzt auch tun.

Danke fᅵr die Tipps

Lars


Lars Meier

unread,
Oct 19, 2009, 2:15:59 PM10/19/09
to
Michael Schumacher schrieb:


Nun ja, die Warnung wegzucasten kann ja nicht die Lösung sein. Es gibt
zwar manche Warnung, die man getrost ignorieren kann, doch bei dieser
bin ich mir nicht so sicher. Zumal ich sie sowohl vom gcc als auch vom
MS Visual Studio Compiler bekomme. Mit dem Cast könnte man so ziemlich
alles an die Funktion übergeben. Wenn Alexander richtig vermutet und die
Warnung auf einen möglichen Darstellungsunterschied zwischen const und
nicht-const-Pointern hinweisen soll, dann wäre dieser cast sogar gerade
falsch.

Markus König

unread,
Oct 20, 2009, 9:44:40 PM10/20/09
to
Lars Meier wrote:

> Michael Schumacher schrieb:
>>
>> Wieso richtig? Er ist ja nicht flasch, blo� weil der Compiler eine


>> Warnung generiert hat (obwohl man die durchaus ernstnehmen sollte!).
>> Deklariere in main() "const char *s;" oder verwende dort den Aufruf
>> "func2 ((const char **) &s);" -- und der Compiler bleibt sprachlos.
>>
>> Warum genau sich "const" und "nicht-const" nicht vertragen, kann Dir
>> Claus sicher in kapitelnumerierter Form aus der Bibel zitieren. ;-)
>>
>

> Nun ja, die Warnung wegzucasten kann ja nicht die L�sung sein. Es gibt


> zwar manche Warnung, die man getrost ignorieren kann, doch bei dieser
> bin ich mir nicht so sicher. Zumal ich sie sowohl vom gcc als auch vom

> MS Visual Studio Compiler bekomme. Mit dem Cast k�nnte man so ziemlich
> alles an die Funktion �bergeben. Wenn Alexander richtig vermutet und die
> Warnung auf einen m�glichen Darstellungsunterschied zwischen const und
> nicht-const-Pointern hinweisen soll, dann w�re dieser cast sogar gerade
> falsch.

Die Einschr�nkung hat nicht unbedingt etwas mit unterschiedlichen internen
Darstellungen zu tun, der Grund liegt tiefer.

K�nnte man einen "x**" an ein Objekt vom Typ "const x**" zuweisen, dann
k�nnte man const umgehen, ohne zu casten:


#include <stdio.h>

void mystery(const int *p)
{
int *q;
const int **pp = &q; /* pp zeigt auf q; zum Glueck ein Fehler! */
*pp = p; /* q zeigt auf *p */
*q = 2; /* veraendert *p! */
}

int main(void)
{
int x = 1;
mystery(&x);
printf("%d\n", x); /* 1 oder 2? */

return 0;
}

Michael Karcher

unread,
Oct 21, 2009, 4:21:02 AM10/21/09
to
Markus König <mar...@stber-koenig.de> wrote:
> Könnte man einen "x**" an ein Objekt vom Typ "const x**" zuweisen, dann
> könnte man const umgehen, ohne zu casten:

>
> #include <stdio.h>
>
> void mystery(const int *p)
> {
> int *q;
> const int **pp = &q; /* pp zeigt auf q; zum Glueck ein Fehler! */
> *pp = p; /* q zeigt auf *p */
> *q = 2; /* veraendert *p! */
> }
>
> int main(void)
> {
> int x = 1;
> mystery(&x);
> printf("%d\n", x); /* 1 oder 2? */
>
> return 0;
> }

C++ ist hier aber flexibler als C. In C++ würde die Zeile

const int * const * pp = &q;

funktionieren, da dann die Zeile "*pp = p" fehlschlagen würde.
In C89 (wenigstens mit gcc 4.4) schlägt die in C++ gültige Zeile
leider auch fehl.

Gruß,
Michael Karcher

Michael Schumacher

unread,
Oct 21, 2009, 6:42:55 AM10/21/09
to
Lars Meier wrote:

Die Compiler-Warnung ist berechtigt (mein Vorschlag, sie per Cast zu
verhindern, allerdings auch). Das hat nichts damit zu tun, daß const-
und veränderliche Objekte unterschiedlich dargestellt werden würden,
sondern damit, daß es zu "interessanten" Nebeneffekten kommen kann:
wenn "func2()" z.B. per "*s = &const_char_array[42];" den Zeiger auf
ein konstantes Zeichen setzt, könnte nach der Rückkehr "main()" mit
"*s = '\0';" ungestraft (jedenfalls, wenn keine HW-Protection existiert)
schreibend auf eine Konstante zugreifen -- daher die Warnung, und warum
sie erst ab doppelter Indirektion (pointer-to-pointer-to-const) auftritt,
läßt sich unter <http://c-faq.com/ansi/constmismatch.html> nachlesen.

Die einzig sinnvolle Möglichkeit, die Warnung zu umgehen, ist der Cast
beim Aufruf von "func2()" -- und zudem natürlich sicherzustellen, daß
deren Parameter "s" nicht "fremdzeigt". Die Alternativen (Warnungen
abschalten, oder das "const" von der Parameterdeklaration entfernen),
sind sicher nicht empfehlenswert.


mike

Lars Meier

unread,
Oct 24, 2009, 5:56:04 AM10/24/09
to
Markus K�nig schrieb:

Da stimmt nat�rlich. Guter Gedanke. An sowas hab ich nicht gedacht.

Lars Meier

unread,
Oct 24, 2009, 6:06:45 AM10/24/09
to


Danke für die Tipps. Da wäre ich nicht drauf gekommen, dass man so const
umgehen kann.

Lars

0 new messages