переменная функция для указателя на функцию - PullRequest
0 голосов
/ 02 января 2019

Есть ли способ привести переменную функцию к указателю на функцию, как это, это законно?Я спрашиваю как для C, так и для C ++, но поскольку эта конструкция существует в обоих языках, я поставил оба вопроса в один.

extern int test(int, ...);
auto testptr = (int(*)(int, int, long)) &test;

Спасибо, thejack

Ответы [ 3 ]

0 голосов
/ 02 января 2019

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

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

Если вы попробуете это на каком-то компиляторе, вы можете обнаружить, что он делает то, что вы ожидаете. Но это не делает его действительным; вполне может сломаться на другой платформе или версии компилятора.

(Вышесказанное верно как для C, так и для C ++.)

0 голосов
/ 02 января 2019

В C эти типы не совместимы.

В разделе 6.2.7 стандарта C , касающемся «Совместимого типа и составного типа», говорится следующее относительносовместимость указателей функций:

3 Составной тип может быть составлен из двух совместимых типов;это тип, который совместим с обоими этими двумя типами и удовлетворяет следующим условиям:

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

...

5 ПРИМЕР С учетом следующих двух деклараций области действия файла:

int f(int (*)(), double (*)[3]);
int f(int (*)(char *), double (*)[]);

Результирующий составной тип для функции:

int f(int (*)(char *), double (*)[3]);

В разделе 6.7.6.3p15 указано:

Для совместимости двух типов функций оба должныуказать совместимые типы возврата. Кроме того, списки типов параметров, если присутствуют оба, должны согласовываться по количеству параметров и при использовании терминатора эллипса; соответствующие параметры должны иметь совместимые типы.Если один тип имеет список типов параметров, а другой тип указывается декларатором функции, который не является частью определения функции и содержит пустой список идентификаторов, список параметров не должен иметь терминатора с многоточием и тип каждого параметра долженбыть совместимым с типом, который является результатом применения продвижения аргумента по умолчанию.Если один тип имеет список типов параметров, а другой тип определен в определении функции, которое содержит (возможно, пустой) список идентификаторов, оба должны совпадать по количеству параметров, и тип каждого параметра прототипа должен быть совместим с типомэто является результатом применения продвижения аргумента по умолчанию к типу соответствующего идентификатора.(При определении совместимости типов и составного типа каждый параметр, объявленный с типом функции или массива, принимается как имеющий скорректированный тип, а каждый параметр, объявленный с квалифицированным типом, принимается как имеющий неквалифицированную версию своего объявленного типа.)

В вашем примере:

int test(int, ...);

Эта функция совместима со следующими функциями:

int (*)();            // a function taking an unknown number of parameters and returns an int
int (*)(int, ...);    // a function taking an int and variable parameters after and returns an int

Но не:

int (*)(int, int, long);    // a function taking an int, an int, and a long, and returns an int

Поскольку оба типа функций задают список параметров, а также потому, что количество параметров и использование многоточия не совпадают, типы несовместимы. Попытка вызова функции через несовместимый указатель вызывает неопределенное поведение согласно разделу 6.3.2.3p8:

Указатель на функцию одного типа может быть преобразован в указатель на функция другого типа и обратно; результат должен сравниться равно оригинальному указателю. Если для вызова используется преобразованный указатель функция, тип которой не совместим с указанным типом, поведение не определено.

0 голосов
/ 02 января 2019

Функции в стиле C - это их собственные особые животные. Их аргументы должны быть развернуты с помощью семейства функций va_list. Нет совместимости с не-переменными функциями, и они не являются макросами, и нет.

Учитывая ваше использование auto Я предполагаю, что вы спрашиваете о C ++, несмотря на двойные теги. Старайтесь избегать подобных функций в C ++.

...