2008-11-20 4 views
15

Absatz 6.7.3.8 der C99-SpezifikationszuständeKonstante Array-Typen in C, Fehler im Standard?

Wenn die Spezifikation eines Array-Typs einen beliebigen Typ-Qualifizierer enthält, ist der Elementtyp so qualifiziert, nicht der Array-Typ. Wenn die Spezifikation eines Funktionstyps einen beliebigen Typqualifizierer enthält, ist das Verhalten nicht definiert.

In der rationale (logische Seite 87, physikalische Seite 94) wird ein Beispiel für das Umsetzen eines flachen Zeigers auf einen Arrayzeiger (mit variabler Länge) angegeben.

void g(double *ap, int n) 
{ 
    double (*a)[n] = (double (*)[n]) ap; 
    /* ... */ a[1][2] /* ... */ 
} 

Sicherlich, wenn das Array ap nicht innerhalb der Funktion geändert, sollte es markiert const werden, aber die Besetzung in

void g(const double *ap, int n) 
{ 
    const double (*a)[n] = (const double (*)[n]) ap; 
    /* ... */ 
} 

nicht beibehält den const Qualifier da (pro 6.7.3.8) es gilt für die Elemente des Ziels anstelle des Ziels selbst, das den Array-Typ double[n] hat. Dies bedeutet, dass Compiler zu Recht beschweren, wenn die entsprechenden Flags (-Wcast-qual für GCC) gegeben. Es gibt keine Möglichkeit, einen const Array-Typ in C anzugeben, aber dieser Cast ist sehr nützlich und "korrekt". Das Flag -Wcast-qual ist nützlich, um den Missbrauch von Array-Parametern zu erkennen, aber die False Positives raten von seiner Verwendung ab. Beachten Sie, dass die Indizierung a[i][j] sowohl lesbarer ist als auch mit vielen Compilern einen besseren Maschinencode erzeugt als , da erstere ermöglicht, dass eine ganzzahlige Arithmetik mit weniger Analyse aus inneren Schleifen geholt wird.

Sollten Compiler dies nur als Sonderfall behandeln, so dass Qualifier von den Elementen zum Array-Typ gehoben werden, um festzustellen, ob ein bestimmter Cast Qualifier entfernt oder ob die Spezifikation geändert werden sollte? Die Zuweisung ist nicht für Array-Typen definiert. Wäre es also für die Qualifizierer schmerzhaft, sich immer auf den Array-Typ und nicht nur auf die Elemente zu beziehen, im Gegensatz zu 6.7.3.8?

+0

Es windet mich wenn '~ (logische Seite N ≡ physikalische Seite N)'. –

Antwort

6

Dies ist ein bekanntes Problem, das in den letzten 10 Jahren bei comp.std.c. mehrmals diskutiert wurde. Die Quintessenz ist, dass der spezielle Fall, den Sie vorgestellt haben, derzeit in Standard C nicht zulässig ist; Sie müssen entweder das Qualifikationsmerkmal entfernen oder davon absehen, einen Zeiger auf ein Array zu verwenden, um auf die qualifizierten Elemente im Array zu verweisen.

Wenn Sie glauben, dass Sie eine gute Idee haben, das Problem zu beheben, können Sie es zur Diskussion an news:comp.std.c senden. Wenn andere zustimmen, dass es eine gute Idee ist, können Sie oder jemand anderes einen Fehlerbericht einreichen, um das Verhalten ändern zu lassen (es gibt mehrere Komitee-Mitglieder, die häufig comp.std.c geben, so Feedback von den Leuten, die möglicherweise die DR überprüfen würden) nützlich sein, vor der Einreichung zu haben). Ich denke, es könnte einige Probleme mit Ihrem Vorschlag geben, Qualifier das Array selbst beeinflussen zu lassen, aber ich müsste darüber nachdenken.

+0

Danke, mir ist klar, dass ich nicht die erste Person bin, die darauf reinkommt. Als ich comp.std.c durchsucht habe, habe ich mehrere Fälle gefunden, in denen die Leute eine ähnliche Aufgabe ohne explizite Besetzung wollten. Mit der Besetzung denke ich, dass das Beispiel absolut sicher ist und Standards erfüllt, obwohl es für den Compiler falsch aussieht. – Jed

+1

C99 hat mehrere Funktionen hinzugefügt, um C für Zahlen, insbesondere für VLA, attraktiver zu machen. Anstelle des Standards, der diesen Fall anspricht, wäre es schön, wenn Compiler feststellen könnten, dass der Cast tatsächlich sicher ist. – Jed

+0

Es kann "sicher" in dem Sinne sein, dass es nicht wie erwartet mit bestehenden Implementierungen funktioniert, aber basierend auf der Art, wie der Standard heute formuliert wird, denke ich, dass die Compiler korrekt sind und dies technisch kein gültiger C-Code ist. –

0

Die Situation mit Zeigern umständlich ist (dh Arrays), aber hier ist meine Erinnerung an die Details:

const double *ap ist ein Zeiger auf einen konstanten Doppel;

double *const ap ist ein konstanter Zeiger auf ein Doppel;

const double *const ap ist ein konstanter Zeiger auf eine konstante Doppel;

Also ich glaube, es ist möglich, zu tun, was Sie fragen, obwohl ich dies seit Jahren nicht versucht habe - die gcc Option, die Sie verwenden, war nicht das letzte Mal, als ich das tat!

EDIT: Diese Antwort ist für die Frage nicht richtig - ich verlasse es die Kommentare unten zu erhalten, die das Problem für Normalsterbliche (oder rostige C-Entwickler ...)

+0

Mein C ist rostig, aber warum macht 'const double * const ap' in der Methodensignatur genau das, was er anfordert? Konstante Array-Referenz und konstante Element-Referenzen? –

+0

Nein, die Konflikte im Beispiel beziehen sich alle auf die Elemente, nicht auf die Zeiger. Eine Eigenart der Sprache (oder des Compilers?) Lässt es so aussehen, als wäre das const-Qualifikationsmerkmal für die Elemente nicht erhalten, wenn es logisch erhalten bleibt. – finnw

+0

Das zweite 'const' ist irrelevant, da es uns nicht interessiert, den Wert des Zeigers' ap' zu ändern. Wir wollen einen "Zeiger auf const double" in "pointer to const Array of double" umwandeln. Dies kann nicht in C ausgedrückt werden, sondern wir werfen stattdessen auf "pointer to array of const double", was die Warnung auslöst. – Jed

1

Mögliche Abhilfe für die Klärung C-Programmierer (nicht aber der Compiler-Designer):

gcc mit -Wcast-qual nicht darüber beschweren:

void g(const double *ap, int n) 
{ 
    int i; 
    struct box 
    { 
     double a[n]; 
    }; 
    const struct box *s = (const struct box *)ap; 

    for (i=0; i<n; ++i) 
    { 
     doStuffWith(s->a[i]); 
     /* ... */ 
    } 
} 

Auch wenn es nicht sehr elegant ist. Das hintere Array-Element a hat auch eine etwas andere Bedeutung zwischen C89 und C99, aber zumindest erhalten Sie den beabsichtigten Effekt.

+0

Es würde tatsächlich aussehen wie 's [i] .a [j]', die der Compiler möglicherweise auf die gleiche Weise optimieren könnte wie 'a [i] [j] '. Diese Lösung vermeidet die Warnung, aber sie fügt eine signifikante Verschleierung hinzu, insbesondere für 4-dimensionale Arrays, die ich verwende. – Jed

Verwandte Themen