GCC:数组类型具有不完整的元素类型

Jos*_*eau 28 c arrays gcc struct

我已经声明了一个结构,我尝试将这些结构的数组(以及双数组和一个整数)传递给一个函数.当我编译它时,我从gcc得到一个"数组类型具有不完整的元素类型"消息.我如何将结构传递给函数我有什么问题?

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

void print_graph(g_node graph_node[], double weight[][], int nodes);
Run Code Online (Sandbox Code Playgroud)

我也试过了struct g_node graph_node[],但我得到同样的东西.

Jon*_*ler 33

这是导致问题的阵列:

void print_graph(g_node graph_node[], double weight[][], int nodes);
Run Code Online (Sandbox Code Playgroud)

必须给出第二个和后续维度:

void print_graph(g_node graph_node[], double weight[][32], int nodes);
Run Code Online (Sandbox Code Playgroud)

或者你可以给指针指针:

void print_graph(g_node graph_node[], double **weight, int nodes);
Run Code Online (Sandbox Code Playgroud)

然而,尽管它们看起来相似,但内部却截然不同.

如果您使用的是C99,则可以使用可变限定的数组.引用C99标准中的示例(第6.7.5.2节数组声明符):

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
}
Run Code Online (Sandbox Code Playgroud)

评论中的问题

[...]在我的main()中,我试图传递给函数的变量是a double array[][],那么我将如何将其传递给函数?传递array[0][0]到它给了我不兼容的参数类型一样,&array&array[0][0].

在你的main(),变量应该是:

double array[10][20];
Run Code Online (Sandbox Code Playgroud)

或类似的东西; 也许

double array[][20] = { { 1.0, 0.0, ... }, ... };
Run Code Online (Sandbox Code Playgroud)

您应该可以使用以下代码传递:

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;
}
Run Code Online (Sandbox Code Playgroud)

用GCC 4.2(i686-apple-darwin11-llvm-gcc-4.2(GCC)4.2.1(基于Apple Inc. build 5658)(LLVM build 2336.9.00))以及GCC编译(到目标代码)使用命令行在Mac OS X 10.7.3上使用4.7.0:

/usr/bin/gcc -O3 -g -std=c99 -Wall -Wextra -c zzz.c
Run Code Online (Sandbox Code Playgroud)

  • +1很棒的答案.值得一提的是函数参数`double weight [] [10]`与`double(*weight)[10]`相同,因为函数声明中的数组参数被视为指向第一个元素的指针(这就是为什么你不需要提供第一维的大小C89§6.7.1,可能在C99的类似位置. (2认同)

Ed *_* S. 7

编译器需要知道二维数组中第二维的大小.例如:

void print_graph(g_node graph_node[], double weight[][5], int nodes);
Run Code Online (Sandbox Code Playgroud)


Lun*_*din 5

发布此内容是为了防止有人遇到这个问题并想知道[]其工作的正式原因和[][]无效的正式原因。有各种各样的规则在起作用:构成有效数组声明的规则以及数组如何作为参数传递给函数的规则“衰减”为指向第一个元素的指针。

\n

C17 6.7.6.2/1 数组声明符:

\n
\n

元素类型不应是不完整类型或函数类型。

\n
\n

在 的情况下double weight[][],元素类型为double[],一种不完整(数组)类型,不允许在任何地方声明,无论是否有参数。因为数组声明的这条规则适用于函数参数的“数组衰减”规则,该规则可在 C17 6.7.6.3/7 函数声明符中找到:

\n
\n

将参数声明为 \xe2\x80\x98\xe2\x80\x98 类型为 \xe2\x80\x99\xe2\x80\x99 的数组应调整为 \xe2\x80\x98\xe2\x80\x98 限定指针\n输入\xe2\x80\x99\xe2\x80\x99

\n
\n

该规则假设我们已经有了数组的声明,这必须根据前面引用的 6.7.6.2 规则来完成。

\n

如果是一维数组double[],那么这是一个不完整的数组类型,但元素类型是double,这是一个完整的类型。根据 C17 6.7.6.2/4 允许这样的数组声明:

\n
\n

如果不存在大小,则数组类型是不完整类型。

\n
\n

每当这样的数组与初始值设定项列表一起使用时,double foo[] = { 1.0f };C17 6.7.9/22 都会声明根据初始值设定项为其指定大小,并在声明结束时转换为完整类型:

\n
\n

如果初始化未知大小的数组,则其大小由带有显式初始化程序的最大索引元素确定。数组类型在其初始化程序列表的末尾\n完成。

\n
\n

如果它没有初始化,而只是函数参数列表的一部分,则前面提到的“数组衰减”规则适用并被double[]替换为double*

\n

现在,如果我们有一个数组参数,例如double [][3],那么它是一个不完整的数组类型,但元素类型double [3]是一个完整的数组类型,因此它是一个有效的声明。在这种情况下,参数将调整为指向此类元素类型的指针double (*)[3]。这就是为什么多维数组参数声明中最左边的数组维度可以被省略的原因 - 实际上我们在那里输入的大小并不重要。

\n