C 以结构指针作为参数的函数原型
我一直在绕着这个问题转。我在extern.h中声明了一个结构: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中,有几个函数接受指向这些结构之一的指针作为参
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 '*'
这是无效的。”结构“”不是类型;'结构队列“”是类型。
也就是说,您需要指定