奇怪的编译器警告C:警告:'结构'里面的参数列表中声明 [英] Strange compiler warning C: warning: ‘struct’ declared inside parameter list

查看:2286
本文介绍了奇怪的编译器警告C:警告:'结构'里面的参数列表中声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚发现在C怪癖,我觉得真的很困惑。在C语言中有可能使用一个指向一个结构已经声明之前。这是一个非常有用的功能,这是有道理的,因为该声明是不相关的,当你只是处理一个指针。我刚刚发现一个角落情况下这是(奇怪)不是真的,不过,我真的不能解释为什么。对我来说,它看起来像在语言设计是一个错误。

I just found a quirk in C that I find really confusing. In C it's possible to use a pointer to a struct before it has been declared. This is a very useful feature that makes sense because the declaration is irrelevant when you're just dealing with a pointer to it. I just found one corner case where this is (surprisingly) not true, though, and I can't really explain why. To me it looks like a mistake in the language design.

把这个code:

#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]

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

To remove this problem we can simply do this:

#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;
}

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

The unexplainable problem is now gone for an unexplainable reason. Why?

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

Note that this question is about the behavior of language C (or possible the compiler behavior of gcc and clang) and not the specific example I pasted.

编辑:

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

I won't accept "the order of declaration is important" as an answer unless you also explain why C would warn about using a struct pointer for the first time in a function argument list but allow it in any other context. Why would that possibly be a problem?

推荐答案

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

To understand why the compiler complains, you need to know two things about C "struct"s:


  • 创建它们(作为一个声明,但尚未定义,类型),只要你为它们命名,所以最先出现结构笑创建了一个声明

  • 他们遵守相同的申报范围的规则,普通变量

  • they are created (as a declared, but not yet defined, type) as soon as you name them, so the very first occurrence of struct lol creates a declaration
  • they obey the same "declaration scope" rules as ordinary variables

结构笑{声明,然后开始定义的结构,它的结构笑; 结构笑* 或别的东西不具有开括号后的申报的步骤,停止。)

(struct lol { declares and then begins defining the structure, it's struct lol; or struct lol * or something else that does not have the open-brace that stops after the "declare" step.)

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

A struct type that is declared but not yet defined is an instance of what C calls an "incomplete type". You are allowed to use pointers to incomplete types, as long as you do not attempt to follow the pointer:

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 */
}

您必须完成的类型,以跟随鼠标指针,换句话说。

You have to complete the type in order to "follow the pointer", in other words.

在任何情况下,需考虑与普通 INT 参数函数声明:

In any case, though, consider function declarations with ordinary int parameters:

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

命名变量 A B 这里声明的括号内,但这些声明需要走出的好让那些在的下次的函数声明不会抱怨他们正在重新申报。

Variables named a and b here are declared inside the parentheses, but those declarations need to get out of the way so that the the next function declaration does not complain about them being re-declared.

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

The same thing happens with struct tag-names:

void gronk(struct sttag *p);

结构sttag 声明了一个结构,然后将声明一扫,就像那些为 A b 。但是,创建了一个大问题:标签不见了,现在你不能以后再命名结构类型!如果你写的:

The struct sttag declares a structure, and then the declaration is swept away, just like the ones for a and b. But that creates a big problem: the tag is gone and now you can't name the structure type ever again! If you write:

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

这定义了一个新的和不同结构sttag ,就像:

that defines a new and different struct sttag, just like:

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

定义了一个新的,不同的 X 在文件级别的范围,从那些不同 somefunc

defines a new and different x and y at the file-level scope, different from the ones in somefunc.

幸运的是,如果你声明(甚至定义)的结构的的你写的函数声明,原型级别宣言指背外范围的声明:

Fortunately, if you declare (or even define) the struct before you write the function declaration, the prototype-level declaration "refers back" to the outer-scope declaration:

struct sttag;
void gronk(struct sttag *p);

现在这两个结构sttag 是相同的结构sttag ,所以当你完成结构sttag 之后,你就完成了 gronk 了。

Now both struct sttags are "the same" struct sttag, so when you complete struct sttag later, you're completing the one inside the prototype for gronk too.

重的问题编辑:它肯定会遭到可以定义不同的结构,联合和枚举标记的作用,使他们的原型泡出自己的封闭范围。这将使这个问题消失。但它并没有定义的方式。因为这是ANSI C89委员会,发明(或偷了,真的,从此-C ++)原型,你可以责怪他们。 : - )

Re the question edit: it would certainly have been possible to define the action of struct, union, and enum tags differently, making them "bubble out" of prototypes to their enclosing scopes. That would make the issue go away. But it wasn't defined that way. Since it was the ANSI C89 committee that invented (or stole, really, from then-C++) prototypes, you can blame it on them. :-)

这篇关于奇怪的编译器警告C:警告:'结构'里面的参数列表中声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆