【问题标题】:"use of undeclared identifier" when typecasting void pointer to struct pointer将 void 指针类型转换为结构指针时“使用未声明的标识符”
【发布时间】:2016-03-28 13:56:05
【问题描述】:

我是 C 的新手,作为一个(经典)练习,我试图在链表上实现一些操作。不过,我还没有走得太远......当我尝试如下声明和初始化根节点时:

#include <stdlib.h>

struct intNode_t {
    int data;
    struct intNode_t* next;
};

int main() {
    struct intNode_t* root = ( intNode_t* ) malloc( sizeof( struct intNode_t ) );
    return 0;
}

编译器 (clang) 在我试图将 malloc 返回的 void 指针类型转换为指向 intNode_t 的指针的地方给出错误“使用未声明的标识符”。我意识到这是一个菜鸟问题,但我在其他地方找不到答案。有什么建议吗?

【问题讨论】:

  • 您在 main 函数中将类型名称 struct intNode_t 拼写了两次。为什么您对拼写不同的名称 intNode_t 的行为不同感到惊讶?
  • 注意:struct intNode_t*intNode_t* 不是一回事。至少在 C 语言中不会。只要去掉那种类型转换,你就会让很多人(包括你自己)开心。
  • 谁告诉你应该转换malloc的结果?请立即停止听那个人说话,因为他们将成为您学习 C 的主要障碍。
  • 你忘记了 struct 之后 main 之前的分号
  • @NiH:因为存在从 void 指针到任何对象指针的隐式转换。看我的回答。 “被告知”的东西是非常危险的,因为 90% 的程序员都是糟糕的程序员,所以通过随机倾听,你很有可能抄袭坏人。

标签: c struct


【解决方案1】:

C 中结构的名称与基本类型和 typedef 的名称空间占据一个单独的名称空间(有关详细信息,请参阅this question)。因此,您的结构类型的名称是struct intNode_t;没有称为intNode_t 的类型。

您可以始终将名称拼写为struct intNode_t,也可以为其创建类型别名。在实际代码中有许多不同的模式:

单独的标签名称,单独的声明:

typedef struct foo_t_ foo_t;

struct foo_t_ { /* ... */ };

这允许您将类型别名放在标头中并将其发布为不透明的 API 类型,而无需透露实际的类型定义。

单独的标签名称,结构定义中的typedef:

typedef struct foo_t_ { /* ... */ } foo_t;

重用名称:

typedef struct foo_t { /* ... */ } foo_t;

这种风格可以让用户在拼写foo_tstruct foo_t时不小心。

不要命名结构:

typedef struct { /* ... */ } foo_t;

但是,在您的代码中,您实际上不需要重复名称,因为 you should not cast the result of malloc 而是依赖于从 void 指针到对象指针的内置隐式转换。你也不应该重复已经知道的类型,而是使用sizeof的表达形式。所以你想要:

int main()
{
    struct intNode_t* root = malloc(sizeof *root);
}

(另请注意,return 0 隐含在 main 中。)

【讨论】:

  • 很好的答案。感谢您抽出宝贵时间进行如此详尽的解释!
  • @NiH:没问题,虽然主要功劳应该归于完成所有艰苦工作的两个相关问题。
【解决方案2】:

无需重复。如果你不重复自己,你可以少犯错误。

struct intNode_t *root;
root = malloc( sizeof *root );
  • 不需要演员表; malloc() 返回一个 void*,它可以与每个(非函数)指针类型交换。
  • sizeof 有两种语法变体:sizeof(type)sizeof expression 第一个需要(),第二个不需要。大多数人更喜欢第二种形式,因为表达式(在您的情况下为 *root )总是会产生正确的类型,因此:大小。

而且,上面的定义+赋值可以组合成一个定义+初始化器,都适合一行:

struct intNode_t *root = malloc( sizeof *root );

【讨论】:

  • 为什么要有单独的声明和赋值?这只会增加噪音并消除局部性。
  • 糟糕。更正。 2) 因为初学者经常对* 在声明/定义和表达式/初始化器中的不同角色感到困惑。
【解决方案3】:

名称intNode_t 未在程序中声明。有声明的结构标签名称intNode_t

所以你需要写

struct intNode_t* root = ( struct intNode_t* ) malloc( sizeof( struct intNode_t ) );

或者您可以通过以下方式引入标识符名称intNode_t

typedef struct intNode_t {
    int data;
    struct intNode_t* next;
} intNode_t;

在这种情况下你可以写

struct intNode_t* root = ( intNode_t* ) malloc( sizeof( struct intNode_t ) );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 2023-02-26
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多