我编写了以下C99代码,并对结构声明感到疑惑。在其中我声明了两个函数指针,它们最终指向主代码中的两个push / pop方法。在函数指针声明中,我已经省略了参数,程序编译好了。它是否正确?我确定我已经读过必须提供的论据。这是正确的C99行为吗?
#include <stdio.h>
#define INITIAL_STACK_SIZE 1000
typedef struct stack
{
int index;
void *stack[INITIAL_STACK_SIZE];
void* (*Pop)(); //<-- Is this correct?
void (*Push)(); //<-- Is this correct?
} stack;
stack CreateStack(void);
void PushStack(stack*, void *);
void *PopStack(stack*);
stack CreateStack(void)
{
stack s = {0, '\0'};
s.Pop = PopStack;
s.Push = PushStack;
return s;
}
void PushStack(stack *s, void *value)
{
if(s->index < INITIAL_STACK_SIZE)
{
s->stack[s->index++] = value;
}
else
{
fputs("ERROR: Stack Overflow!\n", stderr);
}
}
void *PopStack(stack *s)
{
if(s->index > 0)
{
return s->stack[--s->index];
}
else
{
fputs("ERROR: Stack Empty!\n", stderr);
return NULL;
}
}
int main(int argc, char *argv[])
{
stack s = CreateStack();
s.Push(&s, "Hello");
s.Push(&s, "World");
printf("%s\n", (char*)s.Pop(&s));
printf("%s\n", (char*)s.Pop(&s));
return 0;
}
我尝试将参数添加到函数指针但是我得到了Extraneous old-style parameter list.
的编译器错误,所以我猜它是正确的,但是会喜欢另一种意见。
我正在使用Pelles C编译器。
答案 0 :(得分:5)
这是不好的风格(虽然合法)。它会工作,但这意味着编译器无法检查您的参数。所以如果你不小心打电话给你的函数:
s.Push(arg, &s); // oops, reverse the arguments
编译器无法告诉你通话不好。
在ANSI标准化之前,K&amp; R C没有原型;它只支持指定返回类型的声明。当你省略参数时,你正在使用这个古老的特征。
在gcc上,您可以使用选项-Wstrict-prototypes
在使用时启用警告。
答案 1 :(得分:2)
虽然它在GCC下也只有std=c99 -Wall -pedantic
而且没有任何警告,但我很惊讶它完全编译。在我看来,这不是很酷。
我相信使用以下内容会更好:
void* (*Pop)(struct stack*);
void (*Push)(struct stack*, void*);
使用上述开关在GCC 4.2下编译。
否则,看看你的代码,我很可能会认为你用两个参数调用Push会犯一个错误。以上也编译并清除了这种混乱。
答案 2 :(得分:1)
gcc(-pedantic -Wall -std=c99
)对此代码没有问题:
typedef struct stack
{
int index;
void *stack[INITIAL_STACK_SIZE];
void* (*Pop)(struct stack *);
void (*Push)(struct stack *, void *);
} stack;