简体   繁体   English

为什么这段代码在没有前向声明我的结构的情况下编译?

[英]Why does this code compile without forward declaration of my struct?

struct Figlio
{
    char nome[256];
    struct Genitore* padre;
    struct Genitore* madre;
};

struct Genitore
{
    char nome[256];
    struct Figlio* progenie;
};

int main()
{
    return 0;
}

I expected that the above code does not compile since struct Genitore is not declared before Figlio , so a forward declaration of Genitore (ie, struct Genitore; on the top) was needed.我预计上面的代码不会编译,因为struct Genitore没有在Figlio之前声明,所以需要Genitore的前向声明(即顶部的struct Genitore; )。 Instead, in C, it compiles without any problem.相反,在 C 中,它可以毫无问题地编译。

Instead, if I pass a not-yet declared struct pointer to a function, eg,相反,如果我将尚未声明的结构指针传递给函数,例如,

void f(struct st*);

struct st{};

it raises the following warning它会引发以下警告

Warning: 'struct st' declared inside parameter list will not be visible outside of this definition or declaration警告:在参数列表中声明的“struct st”在此定义或声明之外将不可见

So, I don't understand why these different behaviours and, especially, why forward declarations of struct Genitore;所以,我不明白为什么会有这些不同的行为,尤其是为什么前向声明struct Genitore; and struct st;struct st; respectively are not requested.分别不要求。

This is a matter of scope.这是一个范围问题。

First, for the rule regarding a struct tag, section 6.2.1p7 of the C standard states:首先,关于struct标签的规则, C 标准的第 6.2.1p7 节规定:

Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag.结构、联合和枚举标记的范围紧随标记出现在声明标记的类型说明符中之后开始。 ... ...

Which is what allows the appearance of a struct tag to act as a declaration wherever it appears.这就是允许struct标记的出现在任何地方都充当声明的原因。 This also allows a struct to contain a pointer to itself and have it refer to the same type.这也允许结构包含指向自身的指针并使其引用相同的类型。

Then the rules for the scope of identifiers is listed in section 6.2.1p4:那么标识符范围的规则在 6.2.1p4 节中列出:

Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier).每个其他标识符的范围由其声明的位置决定(在声明符或类型说明符中)。 If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope , which terminates at the end of the translation unit.如果声明标识符的声明符或类型说明符出现在任何块或参数列表之外,则标识符具有文件范围,它在翻译单元的末尾终止。 If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope , which terminates at the end of the associated block.如果声明标识符的声明符或类型说明符出现在块内或函数定义中的参数声明列表内,则标识符具有块作用域,终止于关联块的末尾。 If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope , which terminates at the end of the function declarator.如果声明标识符的声明符或类型说明符出现在函数原型(不是函数定义的一部分)的参数声明列表中,则标识符具有函数原型范围,它在函数声明符的末尾终止。 If an identifier designates two different entities in the same name space, the scopes might overlap.如果标识符在同一名称空间中指定两个不同的实体,则范围可能重叠。 If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope).如果是这样,一个实体的范围(内部范围)将严格在另一个实体的范围(外部范围)之前结束。 Within the inner scope, the identifier designates the entity declared in the inner scope;在内部范围内,标识符指定在内部范围内声明的实体; the entity declared in the outer scope is hidden (and not visible) within the inner scope在外部范围内声明的实体在内部范围内隐藏(不可见)

Note in particular the two bolded passages.请特别注意两个加粗的段落。 The implicit declaration of struct Genitore when declaring a pointer to that type as a member of struct Figlio has file scope, since it does not appear in a block statement and does not appear in a function declaration, and therefore is visible from that point down in the source file.当将指向该类型的指针声明为struct Figlio的成员时, struct Genitore的隐式声明具有文件范围,因为它不会出现在块语句中,也不会出现在函数声明中,因此从该点向下可见源文件。

In contrast, the implicit declaration that appears in the function declaration is only in scope for the declaration itself.相反,出现在函数声明中的隐式声明仅在声明本身的范围内。 Such a type declaration is problematic because any potential struct pointer that you pass in will refer to a different type than the one implicitly declared in the function declaration.这样的类型声明是有问题的,因为您传入的任何潜在结构指针都将引用与函数声明中隐式声明的类型不同的类型。

In this declaration在这份声明中

struct Figlio
{
    char nome[256];
    struct Genitore* padre;
    struct Genitore* madre;
};

you declared two pointers to the incomplete type struct Genitore .您声明了两个指向不完整类型struct Genitore的指针。

A pointer type is a complete object type.指针类型是完整的对象类型。

That is in these declarations you declared the incomplete type struct Genitore and objects of the pointer type struct Genitore * .也就是说,在这些声明中,您声明了不完整类型struct Genitore和指针类型struct Genitore *的对象。

The declaration of the structure type struct Genitore is visible in the scope where the structure Figlio is declared (in a file scope or a block scope)结构类型struct Genitore的声明在声明结构Figlio的范围内可见(在文件范围或块范围内)

Another example of introducing an incomplete structure type is a declaration it in a typedef declaration for example另一个引入不完整结构类型的例子是在 typedef 声明中声明 it

typedef struct AA; . .

You can define the structure somewhere below after the typedef declaration in the same scope.您可以在同一范围内的 typedef 声明之后的某处定义结构。

Another example is declaring a structure incomplete type in the return type of a function declaration.另一个例子是在函数声明的返回类型中声明结构不完整类型。 For example例如

struct A f( void );

Again you will need to define the structure at least before the function definition or before a function call.同样,您至少需要在函数定义之前或函数调用之前定义结构。

Here is a demonstration program.这是一个演示程序。

#include <stdio.h>

struct A f( void );

struct A { int x; } f( void )
{
    struct A a = { .x = 10 };

    return a;
};    


int main( void )
{
    struct A a = f();

    printf( "a.x = %d\n", a.x );
}

The program output is程序输出为

a.x = 10

On the other hand, if you will try to dereference a pointer to an incomplete type the compiler will issue an error.另一方面,如果您尝试取消引用指向不完整类型的指针,编译器将发出错误。

In this declaration在这份声明中

void f(struct st*);

the type specifier struct st has the function prototype scope and is not visible outside the function parameter list.类型说明符struct st具有函数原型范围,并且在函数参数列表之外不可见。

From the C Standard (6.2.1 Scopes of identifiers)来自 C 标准(6.2.1 标识符范围)

  1. ...If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator. ...如果声明标识符的声明符或类型说明符出现在函数原型(不是函数定义的一部分)的参数声明列表中,则标识符具有函数原型范围,该范围终止于函数声明符的末尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM