【问题标题】:Is it correct C99 that you don't need to specify arguments in function pointer declarations in structs?不需要在结构中的函数指针声明中指定参数是正确的 C99 吗?
【发布时间】:2010-01-26 22:52:30
【问题描述】:

我编写了以下 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. 的编译器错误,所以我猜它是正确的,但我会喜欢另一种意见。

编辑:我遇到了上面的“Extraneous old-style parameter list”错误,因为我使用 typedef 名称“stack”而不是使用 struct 关键字和“stack”来定义它是我当前定义的结构。

我正在使用Pelles C 编译器。

【问题讨论】:

    标签: c function-pointers c99


    【解决方案1】:

    那是不好的风格(虽然合法)。它会起作用,但这意味着编译器无法检查您的参数。所以如果你不小心这样调用你的函数:

    s.Push(arg, &s);   // oops, reverse the arguments
    

    编译器将无法告诉您调用是错误的。

    在 ANSI 标准化之前,K&R C 没有原型;它只支持指定返回类型的声明。当您省略参数时,您正在使用这个古老的功能。

    在 gcc 上,您可以使用选项 -Wstrict-prototypes 在使用时启用警告。

    【讨论】:

    • 也使用-Wmissing-prototypes。
    【解决方案2】:

    虽然它在 GCC 下也可以使用 std=c99 -Wall -pedantic 甚至没有任何警告,但我很惊讶它完全可以编译。在我看来,这不是很酷。

    我认为使用以下方法会更好:

    void* (*Pop)(struct stack*);
    void (*Push)(struct stack*, void*);
    

    它确实使用上述开关在 GCC 4.2 下编译。

    否则,查看您的代码,我很可能认为您使用两个参数调用 Push 是个错误。以上内容也编译并消除了这种混淆。

    【讨论】:

    • 我实际上在我的代码中犯了一个错误。我使用 typedef 名称“stack”而不是使用带有“stack”的 struct 关键字来定义它是我当前定义的结构。谢谢。
    • 是的,我第一次尝试时也犯了同样的错误,所以我认为这也可能是你的问题。
    • 不要粗鲁,但我在 zneak 前两分钟给出了相同的答案。
    • 是的,对不起,特伦特,但我认为 Zneak 的回答更完整。
    【解决方案3】:

    gcc (with -pedantic -Wall -std=c99) 对这段代码没有问题:

    typedef struct stack
    {
     int index;
     void *stack[INITIAL_STACK_SIZE];
     void* (*Pop)(struct stack *);
     void (*Push)(struct stack *, void *);
    } stack;
    

    【讨论】:

    • gcc 需要 -Wstrict-prototypes 来启用函数声明不是原型的警告。
    • @R Samuel Klatchko,我不确定你的意思,我正在展示带有正确参数的代码可以使用 gcc 编译(即使他报告说它失败了)
    • -Wstrict-prototypes 将捕获非原型的实例(即原始错误版本void* (*Pop)()。您的代码很好,没有这个问题,但使用-Wstrict-prototypes 将防止该问题滑回进入代码。
    猜你喜欢
    • 1970-01-01
    • 2013-01-18
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    相关资源
    最近更新 更多