C 以结构指针作为参数的函数原型

C 以结构指针作为参数的函数原型,c,struct,function-prototypes,C,Struct,Function Prototypes,我一直在绕着这个问题转。我在extern.h中声明了一个结构: typedef struct { char data[Q_SIZE]; int head; int tail; int size; }queue; 在main.c中,我声明了此结构的两个实例: queue rxq, txq; 在其他.c文件中,如果使用这些结构,则将其声明为全局外部,即: extern queue rxq, txq; 在queue.c中,有几个函数接受指向这些结构之一的指针作为参

我一直在绕着这个问题转。我在extern.h中声明了一个结构:

typedef struct {
    char data[Q_SIZE];
    int head;
    int tail;
    int size;
}queue;
在main.c中,我声明了此结构的两个实例:

queue rxq, txq;
在其他.c文件中,如果使用这些结构,则将其声明为全局外部,即:

extern queue rxq, txq;
在queue.c中,有几个函数接受指向这些结构之一的指针作为参数:

int QGetSize(queue * q)
{
    return q->size;
}
我的编译器要求我对这些函数进行原型化,但不喜欢我对它们进行原型化的方式:

int QGetSize(queue *);
ERROR: parse error at near '*'

int QGetSize(queue);
ERROR: invalid functions argument declaration

int QGetSize(struct *);  // this is the one that to me, should work. the other errors make sense.
ERROR: parse error at near '*'

int QGetSize(struct);
ERROR: parse error at near ')'

int QGetSize(struct queue *);
WARNING: struct declared inside parameter list

可能需要注意的是,在prototype.h文件中,它们与此结构不同,不是队列的typedef,如果我尝试对其进行typedef或重新定义,甚至包括最初声明的.h文件,则会出现更多错误。

您可以使用include-guard防止重复包含同一文件:


这样,您就可以自动防止重新定义,就像您在typedefs中观察到的那样。尽管您可能经常看到以下划线开头的宏用作包含保护,但这是一种不好的做法,因为这些名称位于实现的命名空间中,因此是保留的。

您可以使用包含保护防止重复包含同一文件:


这样,您就可以自动防止重新定义,就像您在typedefs中观察到的那样。尽管您可能经常看到以下划线开头的宏用作include-guard,但这是一种不好的做法,因为这些名称位于实现的命名空间中,因此是保留的。

在C中,有两种不同类型的命名空间:struct/union/enum标记名的命名空间和typedef名称的命名空间

typedef struct {
    ...
}queue;
上面的声明声明了一个匿名结构,并为其创建了一个typedef。它在typedef命名空间中只有一个名称,但在标记命名空间中没有名称。这意味着它不能被向前声明。如果要进行转发声明,必须在标记命名空间中为其指定名称


请进一步参考此

在C中,有两种不同类型的命名空间:一种是struct/union/enum标记名的命名空间,另一种是typedef名称的命名空间

typedef struct {
    ...
}queue;
上面的声明声明了一个匿名结构,并为其创建了一个typedef。它在typedef命名空间中只有一个名称,但在标记命名空间中没有名称。这意味着它不能被向前声明。如果要进行转发声明,必须在标记命名空间中为其指定名称


关于您的编译器错误,请进一步参考此

int QGetSize(queue *);
ERROR: parse error at near '*'
这可能是因为你没有包括extern.h或者如果你是, 未定义“队列”的typedef。如果 它找到一个应该是类型但尚未定义为类型的单词

int QGetSize(queue);
ERROR: invalid functions argument declaration
同上。定义必须出现在使用之前

int QGetSize(struct *);
ERROR: parse error at near '*'
这是无效的。”结构“”不是类型;'结构队列“”是类型。 也就是说,您需要在“struct”之后指定类型标记,以便 有意义

int QGetSize(struct);
ERROR: parse error at near ')'
同上。此外,编译器希望在 “struct”,如果没有,就会非常困惑

int QGetSize(struct queue *);
WARNING: struct declared inside parameter list
这意味着尚未定义类型“struct queue”。是哪个 没有typedef结构{…}队列“”与 '结构队列{…}'

因此,这里有一些建议:

首先,标准实践是用 一个“#ifndef”以确保只包含一次:

#ifndef __HDR_H
#define __HDR_H

... code goes here ...

#endif
(uu HDR_H必须是唯一的,并且通常是文件名的变体。)

然后,您可以始终将定义类型的标题包含到 任何使用它们的文件。#ifndef(通常)允许您包括 有罪不罚

其次,您需要找出struct标记之间的区别 和typedefs

结构标记是特定结构定义的名称:

struct queue { ... };       // Defines struct queue

struct queue foo;           // foo is a queue structure.
typedef是现有类型的别名:

typedef int HANDLE;         // HANDLE is just another way of saying 'int'

typedef struct queue QUEUE; // QUEUE is shorthand for 'struct queue'
这两件事截然不同。第一个定义了一个特定的类型 而第二个为现有类型创建新名称。 实际上,您可以将它们结合起来:

typedef struct queue { ... } QUEUE;
而且您经常希望这样做,特别是当“struct queue”包含指针时 到另一个“结构队列”

因此,在这方面:

QUEUE foo;
struct queue bar;
“foo”和“bar”的类型完全相同

(另外,与此相关:在C中,生成typedef是常见的做法 名称全部大写。)

第三,你应该少用typedef。对你来说,我建议 完全摆脱它,总是使用“struct” 关键词。这让我们更容易知道接下来发生了什么 局部结构变量的声明中有“struct”,因此 普通读者可以看到它是一个结构,而不是一个重命名的int

更重要的是,它可以让编译器为您提供更有意义的错误 信息。如果结构未定义且编译器看到某些内容 像这样:

int foo(struct bar x);
它知道bar是一个结构,所以整个东西都是一个参数 声明并可以告诉您“结构栏”未定义。如果是 然而,我看到了这一点:

int foo(BAR x);
它不知道条应该是什么,因此错误消息倾向于 成为一个大WTF?!?!?!?!?相反

最后,如果使用“struct”表单,可以预先声明结构:

struct bar;
int foo (struct bar x);
struct bar { ... };
这很少是必要的,但你偶尔会发现自己 一些真正扭曲的循环依赖。在这种情况下,这可能会导致 你可以摆脱困境。(这也是上面最后一个编译器警告被忽略的原因 警告而不是错误;编译器解释未知 结构参数作为转发声明。这是合法的,但不是一个好主意。)


无论如何,我希望这对您有所帮助,祝您好运。

关于您的编译器错误:

int QGetSize(queue *);
ERROR: parse error at near '*'
这可能是因为你没有包括extern.h或者如果你是, 未定义“队列”的typedef。如果 它找到一个应该是类型但尚未定义为类型的单词

int QGetSize(queue);
ERROR: invalid functions argument declaration
同上。定义必须出现在使用之前

int QGetSize(struct *);
ERROR: parse error at near '*'
这是无效的。”结构“”不是类型;'结构队列“”是类型。 也就是说,您需要指定