views:

216

answers:

3

I have written the following C99 code and was wondering about the struct declaration. In it i declare two function pointers which ultimately point to the two push/pop methods in the main code. In the function pointer declarations i've ommited the arguments and the program compiles ok. Is this correct? I'm sure i've read that the arguments must be supplied. Is this correct C99 behaviour?

#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;
}

I tried adding the arguments to the function pointers but i got a compiler error of Extraneous old-style parameter list. so i'm guessing it's correct, but would love another opinion.

EDIT: I was experiencing the above 'Extraneous old-style parameter list' error because i was using the typedef name 'stack' rather than using the struct keyword with 'stack' to define it was the structure i am currently defining.

I'm using the Pelles C compiler.

+5  A: 

That is bad style (although legal). It will work but it means the compiler can't check your arguments. So if you accidentally call your function like this:

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

the compiler won't be able to tell you the call is bad.

Prior to ANSI standardization, K&R C did not have prototypes; it only supported declarations that specified the return type. When you leave out the arguments, you are using this archaic feature.

On gcc, you can use the option -Wstrict-prototypes to enable warnings when you use them.

R Samuel Klatchko
And use -Wmissing-prototypes too.
Jonathan Leffler
+1  A: 

gcc (with -pedantic -Wall -std=c99) has no problem with this code:

typedef struct stack
{
 int index;
 void *stack[INITIAL_STACK_SIZE];
 void* (*Pop)(struct stack *);
 void (*Push)(struct stack *, void *);
} stack;
Trent
gcc requires the `-Wstrict-prototypes` to enable warnings that the function declaration is not a prototype.
R Samuel Klatchko
@R Samuel Klatchko, I'm not sure what you mean, I am showing that the code with the proper arguments compiles with gcc (even though he reported that it fails with his)
Trent
@Trent - `-Wstrict-prototypes` would catch instances of non prototypes (i.e. the original bad version `void* (*Pop)()`. Your code is fine and doesn't have that problem but using `-Wstrict-prototypes` will prevent that problem from slipping back into the code.
R Samuel Klatchko
+2  A: 

Though it also does under GCC with std=c99 -Wall -pedantic without even a warning about it, I'm surprised it compiles at all. In my opinion, that's not pretty cool.

I believe it's a much better idea to use the following:

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

It does compile under GCC 4.2 using the above switches.

Otherwise, looking at your code, I could very well think you're doing a mistake by calling Push with two arguments. The above also compiles and clears that confusion.

zneak
I actually was making a mistake in my code. I was using the typedef name 'stack' rather than using the struct keyword with 'stack' to define it was the structure i am currently defining. Thanks.
Gary Willoughby
Yeah, I made the same mistake when I first tried it, so I thought that could have been your problem too.
zneak
Not to be rude, but I gave the same answer two minutes before zneak.
Trent
Yeah, sorry Trent, but i thought Zneak's answer was a little more complete.
Gary Willoughby