为什么这段C代码将本地结构体视为指针,而它似乎不是指针?

3
在下面的代码中,“stk”被视为指针。但是,经过几个小时的仔细观察后,我始终看不出它是指针。有人能解释一下我错过了什么吗?
struct T {
    int count;
    struct elem {
        void *x;
        struct elem *link;
    } *head;
};

T Stack_new(void) {
    T stk;
    NEW(stk);
    stk->count = 0;
    stk->head = NULL;
    return stk;
}

我的理解是T是一个结构体,因此stk是一个包含结构体的局部自动变量。它不是指针,但是后来它被当作指针来处理,让我陷入了一种困惑的状态。 更多背景信息 这段代码来自Hanson写的书《C接口与实现》。他创建了一个抽象数据类型的库,暴露了接口并隐藏了实现。栈是他首先介绍的一个。我是一名长期从事编程工作的人,现在才开始深入研究C语言,显然有些语法我还没有理解。谢谢。
如果相关的话,在这里是NEW的定义和new调用的东西:
#define  NEW(p) ((p) = ALLOC((long)sizeof *(p)))

#define ALLOC(nbytes) \
    Mem_alloc((nbytes), __FILE__, __LINE__)

extern void *Mem_alloc (long nbytes,
    const char *file, int line);

3
没错,T这个结构体本身不是指针,但你是否查找过将T定义为指针的typedef呢? - Some programmer dude
1
我讨厌那样的typedef代码,但我同意Joachim的看法,这就是它必须做的。 - Zan Lynx
1
@JoachimPileborg 哦,你说得对。在头文件的其他地方,我发现了这个:"typedef struct T *T;" 这看起来非常令人困惑,所以我很惊讶一个备受推崇的开发者在他备受推崇的代码中使用它,而且这个代码还被认为是非常易读和可维护的。有没有人能帮我理解为什么会有人使用这个习惯用法? - Charlie Flowers
1
让我补充一些公正的内容:该书的模式是每个“模块”定义一个抽象数据类型的接口。在该模块内部,“T”被定义为“此模块公开的类型”。因此,“T”可能是他作为指针typedef的唯一标识符。如果是这样,那么人们可以认为在明确的模式中使用typedef不会像在随机代码中那样具有潜在的混淆性。 - Charlie Flowers
1
更多信息:我找到了一个关于这个问题的SO答案:https://dev59.com/FGkv5IYBdhLWcg3w8FSY#10243348。评论者们在那里辩论“typedef T *T”的利弊。他们提到它被用于不透明指针,有些人喜欢它,有些人不喜欢。感谢大家帮助我解决难题。 - Charlie Flowers
显示剩余6条评论
1个回答

4
在上面的代码片段中,T stk将声明stk为类型为T的变量。然而,类型T没有在任何地方定义,因此代码将无法编译。
如果它改为struct T stk;,则会将stk声明为具有类型struct T的变量。然而,尝试对stk进行解引用将毫无意义,代码再次无法编译。
要使示例有效,您可以添加类似于以下内容:
typedef struct T *T

该代码定义了类型T为指向结构体T的指针。然而,这种定义方式可能会让人感到困惑。


1
谢谢。作为一个新手,我错过了两件事:(1)要声明结构的本地实例,您必须说“struct T stk”而不仅仅是“T stk”。 (2)有人可能仅仅为了避免使用*运算符而对某些内容进行了typedef,这似乎对我来说更有害无益(尽管我承认我是个新手)。顺便说一下,没错。正如我在上面评论的那样,我找到了可以做到这一点的typedef。 - Charlie Flowers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接