Правильно ли в C99, что вам не нужно указывать аргументы в объявлениях указателей на функции в структурах? - PullRequest
5 голосов
/ 27 января 2010

Я написал следующий код 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., так что я предполагаю, что это правильно, но хотелось бы другого мнения.

РЕДАКТИРОВАТЬ: У меня возникла вышеупомянутая ошибка «Список посторонних параметров в старом стиле», потому что я использовал имя определения типа «стек» вместо того, чтобы использовать ключевое слово struct со «стеком», чтобы определить, что это была структура, которую я сейчас определяю.

Я использую компилятор Pelles C .

Ответы [ 3 ]

5 голосов
/ 27 января 2010

Это плохой стиль (хотя и законный). Это будет работать, но это означает, что компилятор не может проверить ваши аргументы. Так что если вы случайно вызвали свою функцию так:

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

компилятор не сможет сказать вам, что вызов плохой.

До стандартизации ANSI у K & R C не было прототипов; он поддерживает только объявления, в которых указан тип возвращаемого значения. Когда вы пропускаете аргументы, вы используете эту архаичную особенность.

В gcc вы можете использовать опцию -Wstrict-prototypes для включения предупреждений при их использовании.

2 голосов
/ 27 января 2010

Хотя он также работает в GCC с std=c99 -Wall -pedantic даже без предупреждения, я удивлен, что он компилируется вообще. На мой взгляд, это не очень круто.

Я считаю, что лучше использовать следующее:

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

Он компилируется в GCC 4.2 с использованием вышеуказанных ключей.

В противном случае, глядя на ваш код, я вполне могу подумать, что вы делаете ошибку, вызывая Push с двумя аргументами. Вышесказанное также компилирует и устраняет эту путаницу.

1 голос
/ 27 января 2010

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;
...