const bei Zeigern auf Zeiger... oder so ähnlich.



  • Hallo zusammen,

    folgendes Problem: ich möchte einer Funktion ein Array von Strings übergeben, also im Prinzip ein char**. Dabei sollen jetzt allerdings sowohl die Zeiger in dem Array als auch die Strings konstant bleiben, während der Zeiger auf das Array selbst innerhalb der Funktion veränderbar sein soll.

    Soweit ich das durchschaue, brauche ich also einen *char const * const **.

    Das kleine Test-Programm hier macht dabei aber Probleme:

    void test(char const * const * foo)
    {
    }
    
    int main()
    {
        char **blah = 0;
        test(blah);
        return 0;
    }
    

    Der Compiler sagt dazu:
    test.c:8: warning: passing argument 1 of ‘test’ from incompatible pointer type

    Wo ist hierbei jetzt der Haken? Soweit ich das sehe unterscheiden sich doch "blah" und "foo" nur in der "constness"... Und es wäre mir neu, daß ich einer Funktion mit konstantem Parameter keinen variablen Wert übergeben kann (umgekehrt wär's natürlich ein Problem, aber das liegt hier ja nicht vor).

    Also, wo liegt mein Denkfehler?

    Danke,
    Dominic



  • Hi,

    das ist ein Konflikt, den ich mit unserem (alten) Compiler auch immer habe: Für ihn gehören die "consts" zum Typen ... und da muß er halt für den Funktionsaufruf eine Typkonversion von "unkonstantem" auf einen "konstanten" Typen machen - und das findet er nicht toll (wenn es auch bei mir nur eine Warning gibt).

    Für mich gehört in dem Fall das const semantisch eher zur Funktion ... ich sage damit, dass diese Funktion diesen Parameter nicht ändern wird - was erst Recht kein Problem darstellen sollte, wenn mir der Aufrufer erlaubt den Parameter zu ändern (wenn ich es denn wollte).

    Ehrlich gesagt: Diese Warnings ignoriere ich inzwischen.

    Ich weiß aber nicht, ob ein aktuellerer Compiler (gemäß C99-Spec) das anders handhabt/en müsste...

    Gruß,

    Simon2.



  • Hi,

    also ein alter Compiler ist das nicht, ich benutze hier gcc-4.1 mit -std=c99, wobei das Problem mit gcc-4.0 und gcc-3.4 aber genauso besteht. Interessanterweise läßt sich mein kleines Test-Programm mit g++ aber kompilieren ohne zu meckern.

    Naja, mit einem expliziten Cast nach *char const * const ** bekomme ich auch die Warnung weg, aber schön ist das nicht... Aber gut zu wissen, daß der Compiler doof ist und nicht ich 😉

    Gruß,
    Dominic



  • Ok, das scheint kein Compiler-Problem zu sein, sondern "das ist halt so" in C.

    ich hab diese Erklärung im C-FAQ gefunden:

    11.10: Why can't I pass a char ** to a function which expects a
    const char **?

    A: You can use a pointer-to-T (for any type T) where a pointer-to-
    const-T is expected. However, the rule (an explicit exception)
    which permits slight mismatches in qualified pointer types is
    not applied recursively, but only at the top level.

    You must use explicit casts (e.g. (const char **) in this case)
    when assigning (or passing) pointers which have qualifier
    mismatches at other than the first level of indirection.


  • Mod

    In C++ ist diese Konvertierung möglich. Bei C bin ich mir nicht so sicher, beim Überfliegen des Standards finde ich folgende Stellen, die relevant sein dürften:

    ISO/IEC 9899.1999:TC2 schrieb:

    6.5.16.1 Simple assignment
    Constraints
    1 One of the following shall hold:
    ...
    — both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

    6.7.5.1 Pointer declarators
    ...
    2 For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

    Wenn man den Punkt in 6.5.16.1/1 mit dem folgenden Punkt (Zuweisung von und zu Pointer auf void) vergleicht (oder auch Vergleich mit Fußnote 94), erkennt man, dass es bei "has all the qualifiers" nur um top-level-Qualifikation des Pointees geht. Alle anderen Qualifikationen bleiben unberührt und unterliegen somit den Bestimmungen von 6.7.5.1/2 - verschiedene Qualifikationen führen dort also zu inkompatiblen Typen.

    Folgendes müßte also möglich sein:

    int *p = 0;
    const int *q = p;
    

    das dagegen nicht:

    int **p = 0;
    const int **q = p;
    

    Ich bin allerdings mit diesem Standard nicht besonders vertraut und hier auch unsicher, das Problem sehe ich zum ersten Mal.


Anmelden zum Antworten