#c #function #constants #typedef
#c #функция #константы #typedef
Вопрос:
Мне было интересно, имеют ли значение указатели на функции, определяющие const, поскольку единственное значение, о котором я мог подумать, — это автоматическая постоянная квалификация его параметров, что, конечно, не так.
Я создал небольшой файл примера (test.c):
typedef void* vop(void*);
vop fn;
const vop cfn;
int main(void){
vop *p_fn = fn;
const vop *cp_fn = fn; // <- gives compiler warning
vop *p_cfn = cfn;
const vop *cp_cfn = cfn;
}
и запустил
gcc -Wall -Wno-unused-variable -c test.c
что приводит к следующему предупреждению:
предупреждение: инициализация создает указатель на квалифицированную функцию ‘__attribute__ ((const))’ из неквалифицированных [-Wdiscarded-qualifiers]
Поэтому «нормально» присваивать «указатель на const vop» переменной типа «указатель на vop», которая, если бы это не был указатель на функцию, давала бы что-то вроде:
предупреждение: инициализация отбрасывает квалификатор ‘const’ из целевого типа указателя [-Wdiscarded-qualifiers]
Но теперь он предупреждает об обратном случае. Итак, возникает вопрос: в чем разница между указателями на функции, квалифицированными const, и теми, которые не являются const-квалифицированными?
Примечание: cppreference содержит следующий абзац:
Если тип функции объявлен с определителем const type (с помощью typedef ), поведение не определено.
Является ли предупреждение, которое я видел, результатом этого «неопределенного поведения», или этот пункт не применяется в данном случае (и если нет, в каком случае он может быть применен)?
Ответ №1:
Тип функции не может иметь для него никакого определителя типа, в том числе const
. При этом поведение не определено.
Из раздела 6.7.3p9 стандарта C:
Если спецификация типа массива включает в себя какие-либо квалификаторы типа, тип элемента определяется таким образом, а не типом массива. Если спецификация типа функции включает в себя какие-либо квалификаторы типа, поведение не определено.
Это объявляет const
тип функции:
const vop cfn;
И это объявляет указатель на const
тип функции:
const vop *cp_fn;
Оба из которых нарушают 6.7.3p9.
Ответ №2:
В чем разница между указателями на функции, квалифицированными const, и теми, которые не являются const-квалифицированными?
const
имеет обычное значение — одно может быть изменено, const
другое — нет. Пример:
void something();
void something_else();
int main() {
void (*normal_pointer)() = something;
normal_pointer = something_else; // all fine
void (*const const_qualified_pointer)() = something;
const_qualified_pointer = something_else; // error
// for fun, let's aad typedef examples
// similar with a typedef, if you want to
typedef void functype();
functype *pnt = something;
pnt = something_else; // all fine
functype *const cpnt = something;
cpnt = something_else; // error
// note that if typedef is already a pointer... then it's already a pointer
typedef void (*functypepnt)();
functypepnt pnt2 = something;
pnt2 = something_else; // all fine
const functypepnt cpnt2 = something;
cpnt2 = something_else; // error
}
Является ли предупреждение, которое я видел, результатом этого «неопределенного поведения», или этот пункт не применяется в данном случае (и если нет, в каком случае он может быть применен)?
Да. vop
является типом функции. const vop
является неопределенным поведением. gcc
выдает предупреждение и игнорирует квалификатор.
Возможно, вместо этого вы захотите const
указать сам указатель, а не указывающий на тип:
vop *const cp_cfn = fn;
Комментарии:
1. Спасибо за ответ, но на самом деле мне просто было любопытно узнать о случае, когда
const
он помещается перед звездочкой. Заголовок вопроса может немного вводить в заблуждение. Должен ли я ее изменить? Этот ответ будет хорошей ссылкой для людей, которые могут наткнуться на этот вопрос и действительно хотят получить «постоянный указатель».