Поведение const квалифицированной функции в C

Мне было интересно, имеют ли какое-либо значение указатели на функции, квалифицирующие 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), поведение не определено.

Является ли предупреждение, которое я увидел, результатом этого «неопределенного поведения» или этот абзац не применяется в этом случае (и если нет, то в каком случае его можно применить)?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
330
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В чем разница между константными указателями функций и указателями, которые не являются константными?

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 ставится перед звездочкой. Название вопроса может немного ввести в заблуждение. Должен ли я изменить его? Этот ответ будет хорошей ссылкой для людей, которые могут наткнуться на этот вопрос и действительно хотят получить «постоянный указатель».

Burdui 17.12.2020 18:09
Ответ принят как подходящий

Тип функции не может иметь квалификатора типа, включая const. Это неопределённое поведение.

Из раздела 6.7.3p9 стандарта C:

Если спецификация типа массива включает какие-либо квалификаторы типа, то квалифицируется тип элемента, а не тип массива. Если спецификация типа функции включает какие-либо квалификаторы типа, поведение не определено.

Это объявляет тип функции const:

const vop cfn;

И это объявляет указатель на тип функции const:

const vop *cp_fn;

Оба из них нарушают 6.7.3p9.

Другие вопросы по теме