Грязный указатель на функцию: как убрать предупреждение?
Как я спросил и ответил в этом посте. У меня есть следующий пример кода.
#include <stdio.h>
char foo() { return 'a'; }
char bar() { return 'b'; }
char blurga() { return 'c'; }
char bletch() { return 'd'; }
char (*gfunclist[])() = {foo, bar, blurga, bletch};
char (*(*x())[])()
{
static char (*funclist[4])() = {foo, bar, blurga, bletch};
return funclist;
}
int main()
{
printf("%c\n",gfunclist[0]());
char (**fs)();
fs = x();
printf("%c\n",fs[1]());
}
Мои вопросы
- Почему
return funclist (с "предупреждением: возврат из несовместимого типа указателя")
а такжевозвращение &funclist
как работает? - Я получаю предупреждение в строке 21 (fs = x();)
предупреждение: назначение из несовместимого типа указателя
, Как убрать это предупреждение?
ADDED
С помощью AndreyT. Я мог бы получить следующий код, который не имеет предупреждений.
#include <stdio.h>
char foo() { return 'a'; }
char bar() { return 'b'; }
char blurga() { return 'c'; }
char bletch() { return 'd'; }
char (*gfunclist[])() = {foo, bar, blurga, bletch};
char (*(*x())[])()
{
static char (*funclist[4])() = {foo, bar, blurga, bletch};
return &funclist;
}
int main()
{
printf("%c\n",gfunclist[0]());
char (*(*fs)[4])();
fs = x();
printf("%c\n",(*fs)[1]());
}
И это менее грязный код с помощью Peoro.
typedef char (*funptr)();
funptr gfunclist[] = {foo, bar, blurga, bletch};
funptr* x()
{
static funptr funclist[4] = {foo, bar, blurga, bletch};
return funclist;
}
int main()
{
printf("%c\n",gfunclist[0]());
funptr *fs;
fs = x();
printf("%c\n",fs[1]());
}
5 ответов
Вы должны решить, используете ли вы C или C++. Эти языки значительно различаются по отношению к таким ситуациям, как ваша.
В C++ указатель на []
"массив" (т. е. массив неопределенного размера) - это совершенно другой тип, нежели "указатель на [N] массив" (т. е. массив указанного размера). Это сразу означает, что у вашего кода нет шансов компилироваться как код C++. Это не "предупреждение", это ошибка. Если вы хотите, чтобы ваш код компилировался как C++, вам нужно указать точный размер массива в типе функции, возвращаемом
char (*(*x())[4])() // <- see the explicit 4 here?
{
static char (*funclist[4])() = {foo, bar, blurga, bletch};
return &funclist;
}
И, конечно же, вы должны вернуться &funclist
, поскольку вы объявляете свою функцию как возвращающую указатель на массив.
В main
объявление получающего указателя как char (**fs)()
не имеет никакого смысла. Функция возвращает указатель на массив, а не указатель на указатель. Вы должны объявить свой fs
как
char (*(*fs)[4])(); // <- pointer to an array
то есть как имеющий тип указателя на массив (обратите внимание на сходство с объявлением функции). И чтобы вызвать функцию через такой указатель, нужно сделать
printf("%c\n", (*fs)[1]());
В языке C явный размер массива в объявлениях указатель на массив может быть опущен, поскольку в C тип "указатель на [массив]" совместим с типом "указатель на массив [N]", но другие точки по-прежнему стоять. Тем не менее, даже в C может иметь смысл более явно указывать этот размер.
Кроме того, вы можете прекратить использование типа указатель на массив и вместо этого использовать тип указатель на указатель. В этом случае ваша функция должна быть определена следующим образом
char (**x())()
{
static char (*funclist[4])() = {foo, bar, blurga, bletch};
return funclist; // <- no `&` here
}
И в main
вы будете работать с ним следующим образом
char (**fs)();
fs = x();
printf("%c\n", fs[1]());
Обратите внимание, что это main
так же, как то, что вы имели в своем первоначальном посте. Другими словами, ваш исходный код представляет собой причудливое сочетание двух совершенно несовместимых методов. Вы должны решить, какой из них вы хотите использовать, и придерживаться его.
Я бы посоветовал вам напечатать указатель на вашу функцию, иначе трудно увидеть, что происходит.
typedef char (*funptr)();
Тем не мение, x
возвращает указатель на char (*(*x())[])
, а также funclist
это не та вещь.
То же самое для fs=x();
: char ((())[]) != char (**)();
...
Если я не ошибаюсь, есть также некоторые ошибки с приоритетом между [] и *...
Это работает нормально:
typedef char (*funptr)();
funptr gfunclist[] = {foo, bar, blurga, bletch};
funptr *x() {
static funptr funclist[4] = {foo, bar, blurga, bletch};
return funclist;
}
funptr *fs;
fs = x();
Выберите либо дополнительный *
или []
в возвращаемом типе x
, не оба.
Когда вы делаете T a[] = { .. };
затем a
объявлен как имеющий тип T[N]
но не как имеющий тип T[]
,
Так что вам нужно поставить в скобках какое-то число.
char (*(*x())[sizeof(gfunclist)/sizeof(*gfunclist)])()
{
return &gfunclist;
}
Это ограничит то, что вы можете вернуть до определенного размера. Это то, где C++ отличается от C, что позволит вам назначить T(*)[N]
для T(*)[]
, В C++ нет таких так называемых правил "совместимости типов". Если вы хотите избавиться от необходимости &
, вам нужно вернуть тип распада массива. Тип элемента вашего массива char(*)()
char (**x())()
{
static char (*funclist[4])() = {foo, bar, blurga, bletch};
return funclist;
}
Используя шаблон идентичности, вы можете сделать ваше объявление более читабельным
template<typename T> struct identity { typedef T type; };
identity<char()>::type **x()
{
static identity<char()>::type *funclist[] = {foo, bar, blurga, bletch};
return funclist;
}
По первому вопросу
cdecl> explain char (*(*x())[])()
declare x as function returning pointer to array of pointer to function returning char
cdecl> explain static char (*funclist[4])()
declare funclist as static array 4 of pointer to function returning char
Таким образом, ожидаемый возвращаемый тип x - это указатель на массив указателей на функции, возвращающие char, но вы возвращаете только массив указателей на функции, возвращающие char. Добавляя &, вы фактически возвращаете указатель на массив указателей на функции, возвращающие char.
Во-вторых, снова ожидаемый тип возврата x - это указатель на массив указателей на функции, возвращающие char, но мы видим,
cdecl> explain char (**fs)();
declare fs as pointer to pointer to function returning char
То, что вы хотите вместо этого, char (*(*fs)[])();
cdecl> explain char (*(*fs)[])();
declare fs as pointer to array of pointer to function returning char