为什么在没有我的结构的前向声明的情况下进行编译?

发布于 2025-01-17 14:38:38 字数 734 浏览 1 评论 0 原文

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

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

int main()
{
    return 0;
}

我预计上面的代码不会编译,因为 struct Genitore 没有在 Figlio 之前声明,因此 Genitore 的前向声明(即 >struct Genitore; 在顶部)是需要的。相反,在 C 中,它编译没有任何问题。

相反,如果我将尚未声明的结构指针传递给函数,例如,

void f(struct st*);

struct st{};

它会引发以下警告

警告:参数列表内声明的“struct st”在此定义或声明之外不可见

因此,我不明白为什么会有这些不同的行为,特别是为什么要向前声明 struct Genitore; 和分别不要求struct st;

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 (i.e., struct Genitore; on the top) was needed. Instead, in C, it compiles without any problem.

Instead, if I pass a not-yet declared struct pointer to a function, e.g.,

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

So, I don't understand why these different behaviours and, especially, why forward declarations of struct Genitore; and struct st; respectively are not requested.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

土豪 2025-01-24 14:38:38

这是一个范围问题。

首先,对于有关 struct 标记的规则,请参阅 C 标准 规定:

结构、联合和枚举标记的作用域在出现后开始
声明标签的类型说明符中的标签。 ...

这使得 struct 标记无论出现在哪里都可以充当声明。这还允许结构包含指向自身的指针并使其引用相同的类型。

那么标识符范围的规则在第6.2.1p4节中列出:

每个其他标识符的范围都由其位置决定
声明(在声明符或类型说明符中)。 如果声明符或
声明标识符的类型说明符出现在任何外部
块或参数列表,标识符具有文件范围,其中
在翻译单元的末尾终止。
如果声明符或
声明标识符的类型说明符出现在块内或
在函数定义中的参数声明列表中,
标识符具有块作用域,该作用域终止于
关联块。 如果声明的声明符或类型说明符
标识符出现在参数声明列表中
函数原型(不是函数定义的一部分)、标识符
具有函数原型范围,该范围在函数末尾终止
函数声明符。
如果一个标识符指定两个不同的
同一名称空间中的实体,范围可能会重叠。如果是这样,则
一个实体的范围(内部范围)将严格在
另一个实体的范围(外部范围)。在内部范围内,
标识符指定在内部作用域中声明的实体;这
在外部范围中声明的实体隐藏(并且不可见)
内部范围

特别注意两个粗​​体段落。将指向该类型的指针声明为 struct Figlio 的成员时,struct Genitore 的隐式声明具有文件作用域,因为它不会出现在块语句中,也不会出现在函数声明中,因此从源文件中的该点向下可见。

相反,出现在函数声明中的隐式声明仅在声明本身的范围内。这样的类型声明是有问题的,因为您传入的任何潜在结构指针都将引用与函数声明中隐式声明的类型不同的类型。

This is a matter of scope.

First, for the rule regarding a struct tag, section 6.2.1p7 of the C standard states:

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. 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:

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.

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.

泪冰清 2025-01-24 14:38:38

在此声明中,

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

您声明了两个指向不完整类型 struct Genitore 的指针。

指针类型是一个完整的对象类型。

也就是说,在这些声明中,您声明了不完整类型 struct Genitore 和指针类型 struct Genitore * 的对象。

结构体类型 struct Genitore 的声明在声明结构体 Figlio 的作用域中可见(在文件作用域或块作用域中)

引入不完整结构体的另一个例子type 是 typedef 声明中的一个声明,例如

typedef struct AA;

您可以在同一范围内的 typedef 声明之后的某个位置定义该结构。

另一个示例是在函数声明的返回类型中声明结构不完整类型。例如

struct A f( void );

,您至少需要在函数定义之前或函数调用之前定义结构。

这是一个演示程序。

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

程序输出是

a.x = 10

另一方面,如果您尝试取消引用指向不完整类型的指针,编译器将发出错误。

在此声明中,

void f(struct st*);

类型说明符 struct st 具有函数原型范围,并且在函数参数列表之外不可见。

来自 C 标准(6.2.1 标识符的范围)

  • ...如果声明符或类型说明符声明了标识符
    出现在函数的参数声明列表中
    原型(不是函数定义的一部分),标识符具有
    函数原型范围,在函数末尾终止
    声明者。
  • In this declaration

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

    you declared two pointers to the incomplete type 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 *.

    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)

    Another example of introducing an incomplete structure type is a declaration it in a typedef declaration for example

    typedef struct A A;.

    You can define the structure somewhere below after the typedef declaration in the same scope.

    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.

    From the C Standard (6.2.1 Scopes of identifiers)

    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.
    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文