Правильно ли C99, что вам не нужно указывать аргументы в объявлениях указателей функций в структурах?
-
23-09-2019 - |
Вопрос
Я написал следующий код на 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.
так что я предполагаю, что это правильно, но хотелось бы услышать другое мнение.
Редактировать:Я столкнулся с вышеупомянутой ошибкой 'Посторонний список параметров старого стиля', потому что я использовал имя typedef 'stack', а не использовал ключевое слово struct с 'stack', чтобы определить, что это была структура, которую я сейчас определяю.
Я использую Pelles C компилятор.
Решение
Хотя это также работает в GCC с std=c99 -Wall -pedantic
я удивлен, что он вообще компилируется, даже не предупредив об этом.На мой взгляд, это не очень круто.
Я считаю, что гораздо лучше использовать следующее:
void* (*Pop)(struct stack*);
void (*Push)(struct stack*, void*);
Он компилируется под GCC 4.2 с использованием вышеуказанных переключателей.
В противном случае, глядя на ваш код, я вполне мог бы подумать, что вы совершаете ошибку, вызывая Push с двумя аргументами.Вышесказанное также компилирует и устраняет эту путаницу.
Другие советы
Это плохой стиль (хотя и законный).Это будет работать, но это означает, что компилятор не может проверить ваши аргументы.Итак, если вы случайно вызовете свою функцию следующим образом:
s.Push(arg, &s); // oops, reverse the arguments
компилятор не сможет сказать вам, что вызов неправильный.
До стандартизации ANSI у K & R C не было прототипов;он поддерживал только объявления, в которых указывался возвращаемый тип.Когда вы опускаете аргументы, вы используете эту архаичную функцию.
В gcc вы можете использовать опцию -Wstrict-prototypes
чтобы включить предупреждения при их использовании.
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;