GCC: Array-Typ hat unvollständigen Elementtyp

Lesezeit: 5 Minuten

Benutzeravatar von Joshua Soileau
Joshua Soileau

Ich habe a erklärt structund ich versuche, ein Array dieser Strukturen (sowie a double Array von Doubles und einer Ganzzahl) in eine Funktion. Ich bekomme ein “Array-Typ hat unvollständigen Elementtyp” Nachricht von gcc, wenn ich es kompiliere. Was habe ich falsch gemacht, wie ich das übergebe struct zur Funktion?

typedef struct graph_node {
  int X;
  int Y;
  int active;
} g_node;

void print_graph(g_node graph_node[], double weight[][], int nodes);

Ich habe es auch versucht struct g_node graph_node[]aber ich bekomme das gleiche.

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Es ist das Array, das Probleme verursacht in:

void print_graph(g_node graph_node[], double weight[][], int nodes);

Die zweite und folgende Dimensionen müssen angegeben werden:

void print_graph(g_node graph_node[], double weight[][32], int nodes);

Oder Sie können einfach einen Zeiger auf Zeiger geben:

void print_graph(g_node graph_node[], double **weight, int nodes);

Obwohl sie ähnlich aussehen, sind sie intern sehr unterschiedlich.

Wenn Sie C99 verwenden, können Sie variabel qualifizierte Arrays verwenden. Zitieren eines Beispiels aus dem C99-Standard (Abschnitt §6.7.5.2 Array Declarators):

void fvla(int m, int C[m][m]); // valid: VLA with prototype scope

void fvla(int m, int C[m][m])  // valid: adjusted to auto pointer to VLA
{
    typedef int VLA[m][m];     // valid: block scope typedef VLA
    struct tag {
        int (*y)[n];           // invalid: y not ordinary identifier
        int z[n];              // invalid: z not ordinary identifier
    };
    int D[m];                  // valid: auto VLA
    static int E[m];           // invalid: static block scope VLA
    extern int F[m];           // invalid: F has linkage and is VLA
    int (*s)[m];               // valid: auto pointer to VLA
    extern int (*r)[m];        // invalid: r has linkage and points to VLA
    static int (*q)[m] = &B;   // valid: q is a static block pointer to VLA
}

Frage in den Kommentaren

[…] In meinem main() ist die Variable, die ich an die Funktion übergeben möchte, a double array[][], also wie würde ich das in die Funktion übergeben? Vorbeigehen array[0][0] hinein gibt mir einen inkompatiblen Argumenttyp, ebenso wie &array und &array[0][0].

In deiner main()die Variable sollte sein:

double array[10][20];

oder etwas ähnlich; kann sein

double array[][20] = { { 1.0, 0.0, ... }, ... };

Sie sollten in der Lage sein, das mit folgendem Code zu übergeben:

typedef struct graph_node
{
    int X;
    int Y;
    int active;
} g_node;

void print_graph(g_node graph_node[], double weight[][20], int nodes);

int main(void)
{
    g_node g[10];
    double array[10][20];
    int n = 10;

    print_graph(g, array, n);
    return 0;
}

Das kompiliert (zum Objektcode) sauber mit GCC 4.2 (i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Basierend auf Apple Inc. Build 5658) (LLVM Build 2336.9.00)) und auch mit GCC 4.7.0 unter Mac OS X 10.7.3 über die Befehlszeile:

/usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c zzz.c

  • Das ist genau das, was ich brauchte, es lässt sich damit gut kompilieren. Ich habe eine andere Frage, in meinem main() ist die Variable, die ich versuche, in die Funktion zu übergeben, ein ‘Double Array'[][]’, also wie würde ich das in die Funktion übergeben? Array übergeben[0][0] darin gibt mir einen inkompatiblen Argumenttyp, ebenso wie &array und &array[0][0].

    – Joshua Soileau

    4. April 2012 um 0:51 Uhr

  • +1 Tolle Antwort. Es könnte auch erwähnenswert sein, dass das Funktionsargument double weight[][10] ist das gleiche wie double (*weight)[10]da Array-Argumente in Funktionsdeklarationen als Zeiger auf das erste Element behandelt werden (weshalb Sie die Größe der ersten Dimension nicht angeben müssen) C89 §6.7.1, wahrscheinlich an einer ähnlichen Stelle in C99.

    – Timothy Jones

    4. April 2012 um 1:26 Uhr

Der Compiler muss die Größe der zweiten Dimension in Ihrem zweidimensionalen Array kennen. Zum Beispiel:

void print_graph(g_node graph_node[], double weight[][5], int nodes);

Posten Sie dies, falls jemand auf diese Frage stößt und sich über die formalen Gründe wundert [] funktioniert und [][] im Allgemeinen nicht. Es gibt verschiedene Regeln im Spiel: die Regeln, was eine gültige Array-Deklaration ausmacht, und die Regeln, wie Arrays, die als Parameter an Funktionen übergeben werden, in einen Zeiger auf das erste Element “zerfallen”.

C17 6.7.6.2/1 Array-Deklaratoren:

Der Elementtyp darf kein unvollständiger oder Funktionstyp sein.

Im Falle von double weight[][]der Elementtyp ist double[], ein unvollständiger (Array-)Typ, der nirgendwo deklariert werden darf, ob Parameter oder nicht. Denn diese Regel der Array-Deklaration gilt vor der Regel des „Array Decay“ von Funktionsparametern, die in C17 6.7.6.3/7 Function declarators zu finden ist:

Eine Deklaration eines Parameters als ”array of type” soll auf ”qualified pointer to type” angepasst werden

Diese Regeln setzen voraus, dass wir bereits eine Deklaration des Arrays haben, was gemäß der zuvor zitierten Regel 6.7.6.2 erfolgen müsste.

Im Falle eines eindimensionalen Arrays double[]dann ist dies ein unvollständiger Array-Typ, aber der Elementtyp ist es double, was ein vollständiger Typ ist. Eine solche Array-Deklaration ist gemäß C17 6.7.6.2/4 erlaubt:

Wenn die Größe nicht vorhanden ist, ist der Arraytyp ein unvollständiger Typ.

Wann immer ein solches Array mit einer Initialisierungsliste verwendet wird, double foo[] = { 1.0f }; dann gibt C17 6.7.9/22 an, dass es abhängig von den Initialisierern eine Größe erhält und am Ende der Deklaration zu einem vollständigen Typ wird:

Wenn ein Array unbekannter Größe initialisiert wird, wird seine Größe durch das größte indizierte Element mit einem expliziten Initialisierer bestimmt. Der Array-Typ wird am Ende seiner Initialisiererliste abgeschlossen.

Wenn es nicht initialisiert wird, sondern einfach Teil einer Funktionsparameterliste ist, dann gilt die zuvor erwähnte Regel des “Array-Zerfalls”. double[] wird durch ersetzt double*.

Falls wir nun einen Array-Parameter wie z double [][3]dann ist es ein unvollständiger Array-Typ, aber der Elementtyp double [3] ist ein vollständiger Array-Typ, also eine gültige Deklaration. In diesem Fall wird der Parameter auf einen Zeiger auf einen solchen Elementtyp angepasst, double (*)[3]. Und das ist der Grund, warum die Array-Dimension ganz links in einer mehrdimensionalen Array-Parameter-Deklaration weggelassen werden kann – es spielt eigentlich keine Rolle, welche Größe wir dort eingeben.

1387030cookie-checkGCC: Array-Typ hat unvollständigen Elementtyp

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy