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

Posted

技术标签:

【中文标题】GCC:数组类型具有不完整的元素类型【英文标题】:GCC: Array type has incomplete element type 【发布时间】:2012-04-17 16:44:45 【问题描述】:

我已经声明了一个struct,并尝试将这些结构的数组(以及一个double 双精度数组和一个整数)传递给一个函数。我在编译时收到来自 gcc 的 “数组类型具有不完整的元素类型” 消息。我将struct 传递给函数的方式有什么问题?

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

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

我也尝试过struct g_node graph_node[],但我得到了同样的结果。

【问题讨论】:

【参考方案1】:

是数组造成了麻烦:

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

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

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

或者你可以只给指针一个指针:

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

然而,虽然它们看起来很相似,但内部却大不相同。

如果您使用的是 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


cmets 中的问题

[...] 在我的 main() 中,我试图传递给函数的变量是 double array[][],那么我该如何将它传递给函数呢?将 array[0][0] 传递给它会给我不兼容的参数类型,&array&array[0][0] 也是如此。

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

double array[10][20];

或类似的东西;也许

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

你应该可以用这样的代码来传递它:

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;

使用 GCC 4.2 (i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.9.00)) 和也可以在 Mac OS X 10.7.3 上使用 GCC 4.7.0 使用命令行:

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

【讨论】:

这正是我所需要的,它编译得很好。我还有一个问题,在我的 main() 中,我试图传递给函数的变量是“双数组 [][]”,那么我该如何将它传递给函数呢?将 array[0][0] 传递给它会给我不兼容的参数类型,&array 和 &array[0][0] 也是如此。 +1 很好的答案。可能还值得一提的是函数参数double weight[][10]double (*weight)[10] 相同,因为函数声明中的数组参数被视为指向第一个元素的指针(这就是为什么您不需要提供第一个维度)C89 §6.7.1,可能在 C99 中的类似位置。【参考方案2】:

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

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

【讨论】:

【参考方案3】:

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

C17 6.7.6.2/1 数组声明器:

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

double weight[][]的情况下,元素类型是double[],一个不完整的(数组)类型,不允许在任何地方声明,参数与否。因为这个数组声明规则先于函数参数的“数组衰减”规则,见于 C17 6.7.6.3/7 函数声明符:

将参数声明为“类型数组”应调整为“限定指针” 输入''

该规则假定我们已经有一个数组声明,这必须按照之前引用的 6.7.6.2 规则来完成。

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

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

每当这样的数组与初始化器列表一起使用时,double foo[] = 1.0f ; 然后 C17 6.7.9/22 声明它的大小取决于初始化器,并在声明结束时变成完整的类型:

如果一个未知大小的数组被初始化,它的大小由最大的索引决定 具有显式初始值设定项的元素。数组类型在其末尾完成 初始化列表。

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

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

【讨论】:

以上是关于GCC:数组类型具有不完整的元素类型的主要内容,如果未能解决你的问题,请参考以下文章

c struct queue error:“数组类型具有不完整的元素类型”

C 定义的结构数组的元素在编译为 C++ 时具有不完整的类型

GCC - 将宏用于函数属性时出现“具有初始化程序但类型不完整”错误

具有内部链接的变量的暂定定义具有不完整的非数组类型:一致的实现显示不同的行为

元素隐式具有“任何”类型,因为类型的表达式

使用 Swift 将具有相同类型的字典分组到具有完整键和值的数组中