我有一个头文件,它引入了一个宏,该宏声明了一个 Stack 结构以及一些与该结构相关的函数。头文件 (Stack.h) 的内容如下所示:
#ifndef STACK_H
#define STACK_H
#include <stddef.h> // size_t
#include <malloc.h> // malloc(), calloc()
#define STACK_DEFAULT_GROWTH_FACTOR 2.0
#define STACK_REALLOC_FAIL -1
#define DECL_STACK(T, Id) \
typedef struct Stack_##Id { \
size_t capacity; \
size_t size; \
float growth_factor; \
T *data; \
} Stack_##Id; \
\
Stack_##Id* Stack_##Id##_New(size_t capacity) { \
Stack_##Id *p = malloc(sizeof(Stack_##Id)); \
if (!p) return NULL; \
T *d = calloc(capacity, sizeof(T)); \
if (!d) { \
free(p); \
return NULL; \
} \
p->capacity = capacity; \
p->size = 0; \
p->growth_factor = STACK_DEFAULT_GROWTH_FACTOR; \
p->data = d; \
return p; \
} \
\
void Stack_##Id##_Free(Stack_##Id *stack) { \
free(stack->data); \
free(stack); \
} \
\
void Stack_##Id##_Push(Stack_##Id *stack, const T item) { \
if (stack->size >= stack->capacity) { \
size_t new_capacity = (size_t)(stack->capacity * stack->growth_factor); \
T *d = realloc(stack->data, new_capacity); \
if (!d) { \
free(stack); \
exit(STACK_REALLOC_FAIL); \
return; \
} \
stack->capacity = new_capacity; \
} \
stack->data[stack->size++] = item; \
} \
\
T Stack_##Id##_Pop(Stack_##Id *stack) { \
return stack->data[--(stack->size)]; \
} \
\
T Stack_##Id##_Peek(const Stack_##Id *stack) { \
return stack->data[stack->size - 1]; \
}
#endif // STACK_H
我有一个 Main.c 文件,其中包含 Stack.h 和另一个名为 Some.h 的头文件。Some.h 还包含 Stack.h,以便使用上述宏来声明一个函数,该函数以某种方式利用已声明的堆栈结构。文件 Some.c 以最简单的形式提供了该函数的定义。我编译并尝试使用以下 makefile 链接该程序:
objects = Main.o Some.o
CC = gcc
flags = -Wall -Wextra
Some.o : Some.c Some.h Stack.h
$(CC) $(flags) -c Some.c Some.h Stack.h
Main.o : Main.c Some.h Stack.h
$(CC) $(flags) -c Main.c Some.h Stack.h
Main : $(objects)
$(CC) $(objects) -o Main
clean: Main
rm $(objects)
以下是Main.c、Some.h和Some.c的内容:Main.c:
#include <stdio.h>
#include "Stack.h"
#include "Some.h"
#ifndef STACK_INT
#define STACK_INT
DECL_STACK(int, int);
#endif
int main() {
Stack_int *stack = Stack_int_New(10);
Stack_int_Push(stack, 100);
printf("%d\n", Stack_int_Peek(stack));
Stack_int_Pop(stack);
Use_stack(stack);
Stack_int_Free(stack);
return 0;
}
一些.h:
#include "Stack.h"
#include <stdio.h>
#ifndef STACK_INT
#define STACK_INT
DECL_STACK(int, int);
#endif
int Use_stack(Stack_int *stack);
一些.c:
#include "Some.h"
int Use_stack(Stack_int *stack) {
Stack_int_Push(stack, 1);
printf("%d\n", Stack_int_Peek(stack));
Stack_int_Push(stack, 2);
printf("%d\n", Stack_int_Peek(stack));
Stack_int_Pop(stack);
return Stack_int_Pop(stack);
}
目标文件编译成功,但我在链接步骤中收到错误,指出函数 Stack_int_New()、Stack_int_Free() 等存在多个函数定义。只有函数存在多个定义,而结构 Stack_int 本身没有(这确实让我感到惊讶)。我期望在 DECL_STACK 宏周围插入的宏扩展保护将阻止多个宏扩展,从而阻止函数(和结构)重新定义。但这并没有发生。我尝试从 makefile 的编译配方中删除头文件,但没有帮助。无论有没有它们,命令都gcc Main.c/Some.c -E
显示预处理器都会插入宏并将其扩展。如果我想在多个 .c 文件中包含我的 Stack.h 文件并使用相同的 Id 声明堆栈,即相同的结构和函数,但没有导致链接错误,我该如何防止多个宏扩展?