Вы делаете [почти] все правильно.
Однако вы должны убедиться, что фактическое объединение union edit_cmd
объявлено, прежде чем использовать его в прототипе функции. Если вы забудете объявить его, компилятор будет обрабатывать union edit_cmd
как объявление совершенно нового типа объединения, который local для прототипа функции. То есть это локальное объявление union edit_cmd
не будет иметь никакого отношения к фактическому объявлению вашего union edit_cmd
, которое вы будете иметь в другом месте.
Это то, что происходит в вашем случае. Об этом вас и предупреждает компилятор. То же самое относится к struct ged
и struct edit_arg
. Видимо, вы забыли включить заголовочные файлы, которые содержат объявления union edit_cmd
, struct ged
и struct edit_arg
.
Например, этот простой код иллюстрирует проблему
void foo(union bar *p);
union bar {
int a;
};
union bar
, объявленный в прототипе foo
, не имеет абсолютно никакого отношения к union bar
, объявленному позже. Первый - локальный по отношению к прототипу, второй - глобальный (то есть тип уровня файла). Если позже попробуйте сделать
union bar u;
foo(&u);
вы получите диагностическое сообщение от компилятора о несоответствии типа аргумент-параметр. Это же несоответствие вызывает вторую группу предупреждений в вашем сообщении (о несовместимых типах указателей при инициализации массива).
Но если вы переставите декларации таким образом
union bar {
int a;
};
void foo(union bar *p);
все будет работать нормально, поскольку union bar
в прототипе теперь относится к ранее объявленному union bar
. В качестве альтернативы вы можете объявить форвард union bar
, как в
union bar;
void foo(union bar *p);
union bar {
int a;
};
Это также заставит компилятор обрабатывать union bar
в foo
как глобальный тип (т.е. тип уровня файла), а не как локальный.
Что касается вызова ваших функций через указатели, это можно сделать как
(*edit_cmds[i].add_arg)( /* arguments go here */ );
или даже без оператора *
edit_cmds[i].add_arg( /* arguments go here */ );
Подводя итог вышесказанному, можно легко решить проблемы, которые вы наблюдаете, - добавить предварительные объявления на уровне файлов для типов struct
и union
перед прототипами функций
.
struct ged;
union edit_cmd;
struct edit_arg;
int edit_translate_concise(struct ged *gedp, const union edit_cmd * const cmd);
int edit_translate_add_arg(union edit_cmd * const cmd, struct edit_arg * const arg);
Более элегантный подход - включить полные определения этих типов до объявления прототипа.