奇怪的编译器警告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
声明一个结构,然后将声明一扫,就像那些为a
和b
。但是这会产生一个很大的问题:标签不见了,现在又不能再给结构类型命名了!如果你写:
struct sttag { int field1; char *field2; };
定义一个新的和不同struct sttag
,就像:
void somefunc(int x) { int y; ... } int x, y;
定义了一个新的和不同x
和y
在文件级别的范围,从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