【问题标题】:How to make a structure extern and define its typedef如何制作外部结构并定义其typedef
【发布时间】:2023-09-16 19:38:01
【问题描述】:

我正在尝试在 C 中实现树算法。我在完全独立的头文件 (b_tree_ds.h) 中声明了一个外部结构。现在我计划在所有想要使用这个结构的源文件中导入该文件。所以我必须在 header 中使用 extern 声明它。

现在的问题是我也想定义它的 typedef。编译器给出了多个存储类的错误。我该怎么做。

typedef extern struct node {
    struct node* left;
    struct node* right;
    int key;    // contains value
}NODE;

实际问题如下,我还是解决不了??? 我最近学习了如何使用带有头文件的多个源文件来使代码可移植和分层。为了做到这一点,我厌倦了使用这个主体创建我的树程序。这是我的文件

b_tree_ds.h - 这将包含树节点数据结构的声明,可以调用实现树的不同功能的各种函数(可能在不同的源文件中)

typedef struct node {
    struct node* left;
    struct node* right;
    int key;    // contains value
}NODE;

当我尝试在 typedef extern struct node 中添加 extern 时,它会给出多个存储类的错误,但如果我错过它,我会收到多个定义的错误。

这是我的其他源文件

traverse.h - 包含遍历函数的声明

void traverse_print (NODE* p);

这里我也收到未知标识符 NODE 的错误

traverse.c - 包含对该函数的定义

#include <stdio.h>
#include "b_tree_ds.h"
#include "traverse.h"

void traverse_print(NODE* p)
{
    if(p->left != NULL)
    {
        traverse_print(p->left);
    }

    if (p->right != NULL)
    {
        traverse_print(p->right);
    }

    printf ("\n%d",p->key);
}

最后是 main.c

#include <stdio.h>
#include "traverse.h"

void main()
{
    // input
    NODE p;

    printf("\nInput the tree");
    input_tree (&p);

    printf("\n\nThe tree is traversing ...\n")
    traverse_print(&p);
}

void input_tree (NODE *p)
{
    int in;
    int c;
    NODE *temp;

    printf("\n Enter the key value for p: ");
    scanf("%d", &in);
    p->key  =in;
    printf ("\n\nIn relation to node with value %d",in);
    printf ("Does it have left child (Y/N): ")
    if ((c = getchar()) == Y);
    {
        //assign new memory to it.
        temp = (NODE *)malloc(sizeof(NODE));
        input_tree(temp);
    }
    printf ("\n\nIn relation to node with value %d",p->key);

    printf ("\nDoes it have right child (Y/N): ")
    if ((c = getchar()) == Y);
    {
        //assign new memory to it.
        temp = (NODE *)malloc(sizeof(NODE));
        input_tree(temp);
    }
}

这是我第一次尝试这种做法,请建议我的程序结构好还是我应该尝试其他方法。

【问题讨论】:

    标签: c extern structure


    【解决方案1】:

    你不能创建一个结构extern。只需在包含保护的受保护标头中定义它,并将该标头包含在您需要的任何地方。

    为 SquareRootOfTwentyThree 编辑

    我在the following way:

    结构类型定义描述了属于 结构体。它包含结构关键字,后跟一个可选的 标识符(结构标记)和用大括号括起来的成员列表。

    结构声明与结构定义具有相同的形式 除了声明没有用大括号括起来的成员列表。

    所以“定义”正是我的意思。

    【讨论】:

    • 一般来说,定义意味着存储的分配,这通常不应该发生在标头中(无论它是否受到保护)。在标题中你做声明。因此,您的答案令人困惑。请参考 C 标准进行论证,而不是在网络上找到一些解释。
    • @SquareRootOfTwentyThree 我认为你在吹毛求疵。我坚持我的回答:在这种情况下,“定义”非常清楚,你不能将它与其他任何东西混淆。
    • 不清楚。您实际上是在说用户应该在标题中 define 结构。只需将其更改为 declare 就可以了..
    • 你不能像 extern 变量那样 extern 结构体(稍作改动)吗?创建一个包含 extern Sruct1 S 的头文件 extern.h,创建另一个包含 typedef struct Sruct1 的头文件 struct.h,然后最后在任何单个 .c 文件中声明 struct Sruct1 S。在需要使用此结构的所有文件中包含标头 extern.h 和 struct.h。这个结构现在可以在任何地方访问
    • 我是这样想的:声明指定标识符。定义指定布局。实例化意味着分配存储。定义中没有分配存储。接受这个作为答案。
    【解决方案2】:

    在 C 中,结构没有链接,只有对象和函数有。所以你可以这样写:

    // header file 'node.h'
    
    typedef struct node_
    {
        /* ... */
    } node;
    
    extern node root_node;
    

    然后在某处提供一个实现:

    // source file
    
    #include <node.h>
    
    node root_node;
    

    【讨论】:

    • 只有对象可以 :-?所以你也在那里包含函数?
    • @cnicutar: 是的,我想是的 :-) 你可以取一个函数的地址,不是吗?
    • 嗯,有一个问题,标准在某处说: 标识符可以表示一个对象;一个函数;结构、联合或枚举的标签或成员;类型定义名称;标签名称;宏名;或宏参数。所以我可以看到对象和函数之间的区别。
    • 什么是 C 中的对象?
    • @Pithikos:具有存储空间并且可以作为值的东西。例如。一个int
    【解决方案3】:

    在你的头文件中像这样声明node.h

    #ifndef NODE_H
    #define NODE_H
    
    #ifdef  __cplusplus
    extern "C" {
    #endif
    
    typedef struct node {
            struct node* left;
            struct node* right;
            int key;    // contains value
        }NODE;
    
    
    #ifdef  __cplusplus
    }
    #endif
    
    #endif  /* NODE_H */  
    

    你可以在任何 c 程序中包含这个头文件并像使用它一样使用它

    NODE* newNode = NULL;
    

    【讨论】:

    • 这会产生错误错误:声明说明符中有多个存储类
    • extern "C" {} 仅在您使用 C++ 编译器时有效。