2012-11-07 66 views
0

我一直在用这个问题的圆圈运行。我有一个结构在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文件,我会得到更多的错误。

+3

对于声明,typedef需要在范围内。 (所以'#include“queue.h”'或者任何头文件被调用。) –

+0

如果我#include“extern.h”(这是struct定义的地方)在extern.h中出现错误:“重新定义的类型无效(队列)的名称“ – ojef

+0

它说以前的定义是什么,它在那里是什么? –

回答

3

可以防止与同一文件的重复包含包括后卫

#ifndef FILE_H 
#define FILE_H 

/* Declarations etc. here. */ 

#endif 

这样,你会自动防止像你这样的typedef所观察到的重新定义。即使您经常可以看到以下划线开头的宏作为包含守护进程,但这是不好的做法,因为这些名称位于实现的名称空间中,因此它们是保留的。

+0

我会更进一步,并建议所有包含文件应该有一个像这样的警卫...和+1提及__GUARD在技术上违反语言规范 – Andrew

0

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

typedef struct { 
    ... 
}queue; 

上述声明声明一个匿名结构和用于它创建一个typedef。它只在typedef名称空间中有一个名称,但在标记名称空间中没有名称。这意味着它不能被宣布。如果你想做一个前向声明,你必须在标签名称空间中给它一个名字。

请继续参考本https://stackoverflow.com/a/612350/1450257

1

对于你的编译器错误:

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

这可能是因为你不包括extern.h或者如果你是, 的“typedef的队列“没有被定义。 C会很困惑,如果 它发现一个单词应该是一个类型但还没有被定义为一个单词。

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

同上。定义必须在使用前出现

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

这是无效的。 'struct'不是一个类型; '结构队列'是类型。 也就是说,你需要在'struct'之后指定类型标记为 有意义。

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

同上。此外,编译器在 '结构'之后期待另一个单词,如果没有它,会变得非常困惑。

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

这意味着类型“结构队列”尚未定义。它 还没有。 'typedef struct {...} queue'与 'struct queue {...}'不同。

所以这里有一些建议:

首先,标准的做法是包装与 一个“的#ifndef”头文件的正文,以确保它只被包含一次:

#ifndef __HDR_H 
#define __HDR_H 

... code goes here ... 

#endif 

(__HDR_H必须是唯一的,通常是文件名的变体)。

然后,您可以随时#include定义您的类型的标头为 任何文件使用它们。 #ifndef(通常)可以让你包含 有罪不罚现象。

其次,你需要弄清楚结构标签 和类型定义之间的区别。

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

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; 

,你经常想,特别是如果“结构队列”包含一个指向 到另一个“结构队列”。

所以在这:

QUEUE foo; 
struct queue bar; 

'富' 和 '酒吧' 具有完全相同的类型。

(另外,半与此相关的:它在C常见的做法作出的typedef 名全部大写。)

第三,您应该谨慎使用的typedef。在你的情况,我建议 完全摆脱它,只是总是使用'​​结构' 关键字。这使得知道发生了什么更容易,因为 本地结构变量在其声明中具有“struct”,所以临时读者可以看到它是一个结构体而不是重命名的int。

更重要的是,它让编译器给你提供更有意义的错误 消息。如果结构是不确定和编译器看到像这样的东西 :

int foo(struct bar x); 

它知道酒吧是一个结构等整个事情是一个参数 声明,可以告诉你,“结构酒吧”是不确定的。如果 认为然而这,:

int foo(BAR x); 

它根本不知道应该什么BAR是,这样的错误信息往往 是一个很大的WTF?!?!?!?!?代替。

最后,如果你用“结构”的形式,你可以预先声明结构:

struct bar; 
int foo (struct bar x); 
struct bar { ... }; 

这是很少必要的,但你会偶尔发现自己 一些真正扭曲循环依赖。在这种情况下,这可以让你摆脱困境。 (这也是为什么最后的编译器上面的警告是 一个警告,而不是一个错误;编译器解释未知 结构参数作为预先声明这是合法的,但一个坏主意)

无论如何,我希望这有助于和祝你好运。

+0

切勿使用以两个下划线开头的标识符,如'__HDR_H'。由于侵入了实现名称空间,因此它是未定义的行为。使用'HDR_H',你很好。 – Jens