奇怪的编译器警告C:警告:在参数列表中声明'struct'

我刚刚在C中发现一个怪癖,我觉得很混乱。在C语言中,可以在声明之前使用指向结构体的指针。这是一个非常有用的特性,因为当你只是处理一个指针时,声明是无关紧要的。然而,我发现了一个角落的情况,但这并不是真的,我真的不能解释为什么。对我来说,在语言设计中看起来像是一个错误。奇怪的编译器警告C:警告:在参数列表中声明'struct'

把这个代码:

#include <stdio.h> 

#include <stdlib.h>

typedef void (*a)(struct lol* etc);

void a2(struct lol* etc) {

}

int main(void) {

return 0;

}

给出:

foo.c:6:26: warning: ‘struct lol’ declared inside parameter list [enabled by default] 

foo.c:6:26: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]

foo.c:8:16: warning: ‘struct lol’ declared inside parameter list [enabled by default]

要删除这个问题,我们可以简单地这样做:

#include <stdio.h> 

#include <stdlib.h>

struct lol* wut;

typedef void (*a)(struct lol* etc);

void a2(struct lol* etc) {

}

int main(void) {

return 0;

}

无法解释的问题现在已经走了一个无法解释原因。为什么?

请注意,这个问题是关于语言C的行为(或可能编译器行为的gcc和叮当),而不是我粘贴的具体示例。

编辑:

我不会接受“声明的顺序是非常重要的”作为回答,除非你也解释了为什么C将警告在函数参数列表使用结构指针的第一次,但允许它在任何其他情况下。为什么这可能是一个问题?

回答:

要理解为什么编译器会抱怨,你需要了解C“结构” S两件事情:

  • 创建它们(作为一个声明,但尚未定义,类型),只要你的名字他们,所以struct lol最先发生创建一个声明
  • 他们遵守相同的“申报范围”的规则,普通变量

struct lol {声明,然后开始定义的结构,它是struct lol;struct lol *或别的东西没有开括号后停止了“申报”的一步。)

即宣告但尚未定义的结构类型是什么C称之为“不完全类型”的实例。你被允许使用指向不完全类型,只要你不要试图跟随指针:

struct lol *global_p; 

void f(void) {

use0(global_p); /* this is OK */

use1(*global_p); /* this is an error */

use2(global_p->field); /* and so is this */

}

你必须完成,以“跟随鼠标指针”,换句话说类型。

在任何情况下,不过,考虑函数声明与普通int参数:

命名

a

b这里的括号内声明

int imin2(int a, int b); /* returns a or b, whichever is smaller */ 

int isum2(int a, int b); /* returns a + b */

变量,但这些声明需要走出的方式,以使next函数声明不会抱怨它们被重新声明。

同样的事情发生与struct标签名称:

void gronk(struct sttag *p); 

struct sttag声明一个结构,然后将声明一扫,就像那些为ab。但是这会产生一个很大的问题:标签不见了,现在又不能再给结构类型命名了!如果你写:

struct sttag { int field1; char *field2; }; 

定义一个新的和不同struct sttag,就像:

void somefunc(int x) { int y; ... } 

int x, y;

定义了一个新的和不同xy在文件级别的范围,从somefunc的有所不同。

幸运的是,如果你写的函数声明之前申报(甚至定义)的结构,原型级别宣言“是指回”到外作用域声明:

struct sttag; 

void gronk(struct sttag *p);

现在,这两个struct sttag s是“相同的”struct sttag,所以当您稍后完成struct sttag时,您也正在完成gronk原型中的一个。


重的问题编辑:它肯定会遭到可以定义不同的结构,联合和枚举标记的作用,使它们的原型“泡出”自己的封闭范围。这会让问题消失。但它没有这样定义。由于它是ANSI C89委员会发明的(或者真的从当时的C++中偷取)原型,所以你可以将它归咎于它们。 :-)

回答:

这是因为,在第一个示例中,此结构先前未定义,因此编译器会尝试将此结构的第一个引用视为定义。

一般来说,C语言的声明顺序很重要。您使用的所有内容都应该以某种身份提前正确声明,以便编译器可以在其他上下文中引用它时对其进行推理。

这不是语言设计中的错误或错误。相反,我相信这是一种选择,可以简化首批C编译器的实现。前向声明允许编译器一次转换源代码(只要知道诸如尺寸和偏移的一些信息)。如果情况并非如此,编译器只要遇到无法识别的标识符就能够在程序中来回切换,因此要求其编码发射循环要复杂得多。

回答:

编译器警告你一个向前声明的struct lol。 C允许你这样做:

struct lol;  /* forward declaration, the size and members of 

struct lol are unknown */

定义自引用的结构时,这是最常用的,但界定是从来没有在头文件中定义私有结构时,它也很有用。因为后者的使用情况下,允许以声明接收功能或返回指向不完全结构:

void foo(struct lol *x); 

然而,仅仅使用未声明的结构在函数声明中,像你一样,会被解释为本地struct lol的不完整声明,其范围受函数限制。这个解释是由C标准规定的,但它没有用(没有办法构造传递给函数的struct lol),并且几乎肯定不是程序员的意图,所以编译器警告。

以上是 奇怪的编译器警告C:警告:在参数列表中声明'struct' 的全部内容, 来源链接: utcz.com/qa/266010.html

回到顶部