标头可以使用源文件中定义的宏定义吗?

时间:2019-11-09 03:30:11

标签: c arrays header stack include

我正在尝试使用固定长度的数组实现堆栈。我想创建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

这可能吗?在源文件中定义了宏,但在头文件中使用了宏吗? 谢谢

2 个答案:

答案 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预处理程序,并且可以查看代码在发送给编译器之前如何组合在一起。