Что означает указатель на постоянную функцию?

Указатели могут быть объявлены как указывающие на изменяемые (неконстантные) данные или указатель на постоянные данные.
Указатели могут быть определены так, чтобы указывать на функцию.

Мои коллеги и я обсуждали использование "const" с указателями, и возник вопрос о том, как использовать const с указателями функций.

Вот несколько вопросов:

  • В чем смысл указателя на постоянную функцию по сравнению с указатель на непостоянную функцию?
  • Может ли функция быть const?
  • Может ли функция быть непостоянной (изменчивой)?
  • Каков правильный (безопасный) синтаксис для передачи указателя функции?

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

typedef void (*Function_Pointer)(void); // Pointer to void function returning void.

void function_a(Function_Pointer p_func); // Example 1.
void function_b(const Function_Pointer p_func); // Example 2.
void function_c(Function_Pointer const p_func); // Example 3.
void function_d(const Function_Pointer const p_func); // Example 4.

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

Данные, переменная или указатель памяти позволяют использовать приведенные выше комбинации.
Таким образом, вопросы таковы: может ли указатель функции иметь одни и те же комбинации и что подразумевается под указателем на функцию const (например, пример 2)?

Ответы

Ответ 1

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

Обратите внимание, что хотя он и отличается, вы можете иметь указатель на константу, указатель на функцию, возвращающую const, и т.д. По сути, все, кроме самой функции, может быть const. Рассмотрим несколько примеров:

// normal pointer to function
int (*func)(int);

// pointer to const function -- not allowed
int (const *func)(int);

// const pointer to function. Allowed, must be initialized.          
int (*const func)(int) = some_func;

// Bonus: pointer to function returning pointer to const
void const *(*func)(int);

// triple bonus: const pointer to function returning pointer to const.
void const *(*const func)(int) = func.

Что касается передачи указателя на функцию в качестве параметра, это довольно просто. Обычно вы хотите просто передать указатель на правильный тип. Однако указатель на любой тип функции можно преобразовать в указатель на какой-либо другой тип функции, затем вернуться к исходному типу и сохранить исходное значение.

Ответ 2

Согласно спецификации C (C99, раздел 6.7.3):

Свойства, связанные с квалифицированными типами, имеют смысл только для выражения, которые являются lvalues.

Когда спецификация говорит "квалифицированные типы", это означает вещи, определенные с помощью ключевого слова const, restrict или volatile. Функции Snice не lvalues, ключевое слово const для функции не имеет смысла. Возможно, вы ищете какое-то расширение для компилятора. Некоторые компиляторы будут вызывать ошибку, если вы попытаетесь объявить функцию как const.

Вы уверены, что ищете указатель на постоянную функцию, а не постоянный указатель на функцию (то есть указатель, который const, а не функция)?

Относительно # 4: см. это руководство для полезного обзора создания, передачи и использования указателей функций.

Ответ 3

В C нет функции const. const является классификатором типа, поэтому его можно использовать только для того, чтобы квалифицировать тип, а не функцию. Может быть, вы имеете в виду указатель const на функцию или указатель не константы на функцию?

В С++ методы могут быть const. Если метод const, это означает, что после вызова этого метода объект, содержащий этот метод, будет находиться в том же состоянии, что и до вызова метода (ни одна из переменных экземпляра [1] не была изменена). Таким образом, вы можете указать на метод const и метод non-const, и эти методы отличаются.

Вы можете принять указатель на функцию в списке аргументов как retType (*variableName)(arguments).

[1] Если они не являются mutable.

Ответ 4

В C функции могут быть const, если вы находитесь в мире GCC! Функции могут быть объявлены const с помощью атрибутов, прикрепленных к объявлениям функций и других символов. Он в основном используется для предоставления информации компилятору о том, что делает функция, даже несмотря на то, что ее тело недоступно, чтобы компилятор мог делать с ним какие-то оптимизации.

Постоянная функция обычно определяется в терминах функции a pure.

Чистая функция - это функция, в основном не имеющая побочного эффекта. Эта означает, что чистые функции возвращают значение, которое рассчитывается на основе заданные параметры и глобальную память, но не могут влиять на значение любого другая глобальная переменная. Чистые функции не могут разумно не иметь возврата (т.е. имеют тип возврата void).

И теперь мы можем определить, что такое функция const,

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

Здесь const не означает ничего о функциональной изменчивости. Но это функция, которая не затрагивает глобальную память. Вы можете назначить обычные указатели на такие функции. Как бы то ни было, область кода в целом (забывая самонастраивающийся код на некоторое время) должна быть RO, и вы не можете изменить ее с помощью обычного указателя.

Прочитайте полную проницательную статью здесь.

Итак, когда дело доходит до функций константы GCC, мы говорим об оптимизации и неспособности функции.

Ответ 5

1. В чем смысл указателя на постоянную функцию по отношению к указателю на непостоянную функцию?

Нет никакой разницы между константой и не-const: сама функция не модифицируется

Примечание. В С++, если функция является функцией-членом класса, const означает, что состояние объекта внутри этой функции не может быть изменено (переменные-члены, назначенные, вызываются не-константные функции memeber). В этом случае ключевое слово const является частью сигнатуры функции-члена и поэтому имеет значение в терминах указателя.

2. Может ли функция быть const?

См. выше.

3. Может ли функция быть непостоянной (изменчивой)?

См. выше

4. Каков правильный (безопасный) синтаксис для передачи указателя функции?

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

Для С++: указатели на функции-члены не гарантируются преобразованием в указатели на свободные функции

Ответ 6

1. Синтаксически нет места для размещения константы, чтобы константа содержимого была постоянной.

Вы столкнетесь с ошибкой "function is not l-value", независимо от того, есть ли у вас const или нет.

typedef void (* FUNC)(void);
FUNC pFunc;
pFunc = 0;     // OK
*pFunc = 0;    // error:  Cannot assign to a function (a function is not an l-value)

typedef void (* const FUNC)(void);
FUNC pFunc;
pFunc = 0;     // error  (const)
*pFunc = 0;    // error:  Cannot assign to a function (a function is not an l-value)

typedef void (const * FUNC)(void);   // error:  <cv-qualifier>  (lol?)

2 и 3. Указатели функций - да. Содержимое функции не похоже.

4. Я не думаю, что есть способ сделать передачу указателя функции более безопасной. Со всеми константами в мире единственное, что вы можете защитить, это то, что "SetCallback" не может изменить собственную локальную копию параметра.

typedef void (* const FUNC)(void);
void SetCallback(const FUNC const pCallback)
{
  FUNC pTemp = pCallback;   // OK  (even though pTemp is not const!!)
  pCallback = 0;            // error  (const)
}