Мне было интересно, имеют ли какое-либо значение указатели на функции, квалифицирующие 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, и указателями, не являющимися константными?
Примечание. В cppreference есть следующий абзац:
Если тип функции объявлен с квалификатором типа const (через использование typedef), поведение не определено.
Является ли предупреждение, которое я увидел, результатом этого «неопределенного поведения» или этот абзац не применяется в этом случае (и если нет, то в каком случае его можно применить)?





В чем разница между константными указателями функций и указателями, которые не являются константными?
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;
Тип функции не может иметь квалификатора типа, включая const. Это неопределённое поведение.
Из раздела 6.7.3p9 стандарта C:
Если спецификация типа массива включает какие-либо квалификаторы типа, то квалифицируется тип элемента, а не тип массива. Если спецификация типа функции включает какие-либо квалификаторы типа, поведение не определено.
Это объявляет тип функции const:
const vop cfn;
И это объявляет указатель на тип функции const:
const vop *cp_fn;
Оба из них нарушают 6.7.3p9.
Спасибо за ответ, но на самом деле мне просто был любопытен случай, когда
constставится перед звездочкой. Название вопроса может немного ввести в заблуждение. Должен ли я изменить его? Этот ответ будет хорошей ссылкой для людей, которые могут наткнуться на этот вопрос и действительно хотят получить «постоянный указатель».