我正在尝试使用固定长度的数组实现堆栈。我想创建Stack的多个实例,所以我的堆栈实现在我的stack.h标头中。
.htaccess
但是,我想让数组的SIZE保持私有,所以我在stack.c中定义了它。
stack.h
#ifndef STACK_H
#define STACK_H
typedef int Item;
typedef struct stack{
Item array[SIZE];
int current_size;
}Stack;
Stack *create_stack(void);
void push_stack(Stack *stack, Item value);
Item pop_stack(Stack *stack);
#endif
这可能吗?在源文件中定义了宏,但在头文件中使用了宏吗? 谢谢
答案 0 :(得分:1)
从技术上讲,您应该将#include
预处理程序指令视为“复制和粘贴”指令。
这基本上意味着最终结果是一个文件,其中包含指定顺序的所有文本。
当然,在这种情况下,您的代码中有错误,因为SIZE
仅在使用后 定义。
考虑,在stack.c
中:
#define SIZE 100
#include "stack.h"
这将允许在SIZE
中使用stack.h
。
此外,通过不在标头中定义SIZE
(至少作为回退值),如果不先手动定义SIZE
,将无法在任何地方包含标头。
考虑,在标题中添加:
#ifndef SIZE
#define SIZE 10
#endif
恕我直言,这种方法不是使用此功能的理想方法,但这应该可以回答您的问题。
恕我直言,最好的方法是使用不完整的类型或“灵活数组”。
例如,您可以使用以下方式定义类型:
typedef struct stack{
int current_size;
Item array[];
} Stack;
然后分配足够的内存来使用(例如)管理堆栈大小:
Stack * s = malloc(sizeof(*s) + (SIZE*sizeof(Item)));
但是,我可能会选择使类型成为不透明的指针。
这意味着只能使用功能访问数据。
使用不透明的指针会提供更强的分隔性。
这也很有帮助,允许您将来在不破坏ABI /向后兼容性的情况下更新数据类型。
即,在标题中将您自己限制为:
typedef struct stack Struct;
函数将使用指向不完整类型的指针。
Stack *create_stack(void);
这将保证没有使用标头的人可以访问数据(他们将获得有关访问不完整类型的错误)。
C文件将仅在内部使用时定义该结构:
struct stack{
Item array[SIZE];
int current_size;
};
或者,如上所述,使用动态尺寸方法:
struct stack{
int current_size;
Item array[];
};
Stack *create_stack(size_t size)
{
Stack * s = malloc(sizeof(*s) + (size * sizeof(*s->array)));
// ....
return s;
}
P.S。 -恕我直言
关于命名的注释……您似乎正在使用CamelCase命名约定。
在C语言中,您会发现大多数开发人员倾向于使用snake_case而不是CamelCase来命名事物。
此外,typedef通常具有一个后缀,类似于POSIX使用的(保留的)_t
后缀和某些标准类型(即,结构类型可能以_s
结尾)。
这只是我的个人观点,但是作为长期的代码阅读器,我发现阅读与某种语言提供的标准库样式相匹配的代码更加容易。显然,并非所有人都同意我的观点。
使用这些命名约定,我将这些类型命名为:
typedef int item_i;
typedef struct stack{
int current_size;
item_i array[SIZE];
} stack_s;
答案 1 :(得分:-1)
是的,这很有可能。您只需要将#define SIZE 100
行放在#include "stack.h"
行上方。 C预处理程序基本上会将头文件的内容复制/粘贴到包含它的位置,因此,如果在包含它的位置上方定义SIZE
,则它将把头文件的内容放入其中在它下面编译就可以了。
旁注:根据您的设置,您可能可以使用cpp source.c
仅运行C预处理程序,并且可以查看代码在发送给编译器之前如何组合在一起。