Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518

Operator[] for pointer-to-function

05.05.2021, 00:19. Показов 2703. Ответов 21

Студворк — интернет-сервис помощи студентам
Всем привет!

Внимательно посмотрите на код, и скажите: всё ли с ним в порядке?
C++
1
2
3
4
5
6
7
8
#include <iostream>
 
int foo() { return 1; }
int main()
{
    int(*p)() = foo;
    std::cout << p[0]();
}
Кликните здесь для просмотра всего текста
gcc успешно компилирует, приложение успешно работает.
Но при этом компилятор генерирует предупреждение:
Code
1
2
3
4
62936928/source.cpp: In function ‘int main()’:
62936928/source.cpp:7:21: warning: pointer to a function used in arithmetic [-Wpointer-arith]
     std::cout << p[0]();
                     ^
msvc отказался компилировать этот код:
Code
1
Error C2109: subscript requires array or pointer type


Что говорит по этому поводу стандарт языка?
Корректно ли применять operator[] к указателю-на-функцию?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
05.05.2021, 00:19
Ответы с готовыми решениями:

friend function C++ and operator ::
привет подскажите пожалуйста в чем ошибка? где не понимаю? допустим есть класс class foo{ public:

Указатель динамической памяти и ошибка Invalid pointer operator
Здравствуйте!У меня программа вычисляет простые числа до 32765 и вывод повторяется три раза в один файл.Но выдается ошибка &quot;204...

Несоответствие Pointer и addr(function)
Доброго Времени Суток! Пишу программу на Delphi XE. Но почему-то на строках ............... TTextRec(Output).InOutFunc :=...

21
фрилансер
 Аватар для Алексей1153
6455 / 5657 / 1129
Регистрация: 11.10.2019
Сообщений: 15,069
05.05.2021, 08:03
а вот так нет никакого оператора []

C++
1
std::cout << (*(p+0))();
но предупреждение тоже есть )

Добавлено через 3 минуты
ему, похоже, вообще по барабану, сколько раз разыменовывать указатель на функцию

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
 
int foo() { return 1; }
int main()
{
    int(*p)() = foo;
    std::cout <<        p      ();
    std::cout <<       (p+0)   ();
    std::cout <<     (*(p+0))  ();
    std::cout <<   (*(*(p+0))) ();
    std::cout << (*(*(*(p+0))))();
    std::cout <<p[0][0][0]();
}
0
248 / 70 / 9
Регистрация: 22.07.2018
Сообщений: 321
05.05.2021, 12:36
Цитата Сообщение от eva2326 Посмотреть сообщение
Что говорит по этому поводу стандарт языка?
Корректно ли применять operator[] к указателю-на-функцию?
Говорит что некорректно.
1
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518
05.05.2021, 15:37  [ТС]
Цитата Сообщение от argcargv Посмотреть сообщение
Говорит что некорректно.
Что конкретно он говорит?
0
248 / 70 / 9
Регистрация: 22.07.2018
Сообщений: 321
05.05.2021, 15:44
Лучший ответ Сообщение было отмечено eva2326 как решение

Решение

Цитата Сообщение от eva2326 Посмотреть сообщение
Что конкретно он говорит?
...
Цитата Сообщение от https://timsong-cpp.github.io/cppwp/n4861/expr.sub#1
A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall be a glvalue of type “array of T” or a prvalue of type “pointer to T” and the other shall be a prvalue of unscoped enumeration or integral type. The result is of type “T”. The type “T” shall be a completely-defined object type.
1
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518
05.05.2021, 15:59  [ТС]
Цитата Сообщение от argcargv Посмотреть сообщение
or a prvalue of type “pointer to T”
Мне кажется, тут какая то чушь написана.

Хотите сказать, что этот код не корректен???

C++
1
2
3
4
5
6
7
8
#include <cassert>
int main()
{
    int v = 33;
    int* p = &v;
    int& r = p[0];     // lvalue
    assert(r == 33);
}
К тому же, сама формулировка:
Цитата Сообщение от argcargv Посмотреть сообщение
“pointer to T”
В равной степени подходит как к указателям-на-данные, так и к указателем-на-функции.


Получется, что либо operator[] можно применять только к prvalue-pointer-expression, а значит код в стартопике, и код выше некорректный; либо можно применять к любым pointer-expression, а значит оба образца являются корректными.

Но тогда получается, что ваше заявляение:
Цитата Сообщение от argcargv Посмотреть сообщение
Говорит что некорректно.
Неверно.
0
248 / 70 / 9
Регистрация: 22.07.2018
Сообщений: 321
05.05.2021, 16:08
Цитата Сообщение от eva2326 Посмотреть сообщение
Хотите сказать, что этот код не корректен???
Код корректен, ибо https://timsong-cpp.github.io/... sentence-1
Цитата Сообщение от eva2326 Посмотреть сообщение
К тому же, сама формулировка:
“pointer to T”
В равной степени подходит как к указателям-на-данные, так и к указателем-на-функции.
Ну подходит и подходит.
Цитата Сообщение от eva2326 Посмотреть сообщение
Получется, что либо operator[] можно применять только к prvalue-pointer-expression, а значит код в стартопике, и код выше некорректный; либо можно применять к любым pointer-expression, а значит оба образца являются корректными.
Бывает полезно читать цитаты из стандарта до конца.
1
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518
05.05.2021, 16:18  [ТС]
Цитата Сообщение от argcargv Посмотреть сообщение
Бывает полезно читать цитаты из стандарта до конца.
Цитата Сообщение от argcargv Посмотреть сообщение
The result is of type “T”. The type “T” shall be a completely-defined object type.
ММММммм!!!!

Для "указателя-на-функцию" результат получается "функцией", но "функция" не является "object type", и поэтому, данное правило для "указателей-на-функцию" не пременимо.

Так?
0
248 / 70 / 9
Регистрация: 22.07.2018
Сообщений: 321
05.05.2021, 16:19
Цитата Сообщение от eva2326 Посмотреть сообщение
Для "указателя-на-функцию" результат получается "функцией", но "функция" не является "object type", и поэтому, данное правило для "указателей-на-функцию" не пременимо.
Так?
Да.
1
Эксперт CЭксперт С++
 Аватар для liv
5120 / 4574 / 855
Регистрация: 07.10.2015
Сообщений: 9,462
05.05.2021, 16:27
Размышления вслух... Взгляд с другой стороны...
При вызове функции по указателю происходит неявное разыменовывание, т.е. вызов функции по адресу из указателя.
Т.е. так прекрасно работает:
C++
1
2
    int(*p)() =  foo ;
    std::cout << p();
А обращение p[0] приводит к ошибке...
Но, если сделать так:
C++
1
2
    int(*p[])() = { foo };
    std::cout << p[0]();
то все отработает. Т.к. явно сказали, что имеем массив указателей на функции.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
05.05.2021, 17:34
liv, не очень понятно почему здесь "но". Во втором случае совсем другая ситуация, [] применяются к массиву указателей на функцию. Результат такой операции - указатель на функцию. Указатель на функцию - это объектный тип, поэтому он может быть результатом []. В первом случае [] применяются к указателю на функцию, результат такой операции - функция. Функция не объектный тип, поэтому это приводит к ошибке.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
05.05.2021, 17:46
Цитата Сообщение от liv Посмотреть сообщение
А обращение p[0] приводит к ошибке...
liv, я думаю, это от компилятора зависит. Мой mingw это компилирует и генерирует рабочий код. Но это вряд ли нормально. Для меня оператор индексирования на указателях это удобное замещение над операцией сложения. То есть:
C++
1
2
int *ptr;
bool trushka = ptr[1]==ptr+1 ;// true
а указатели на функции не предоставляют адрес, а адресная арифметика бессмысленна, даже если компилятор делает вид, что он чего-то складывает (или вычитает).
C++
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;
    int foo(){ cout<<"foo!\n";}
    int main()
    {
    int (*pf)()=foo;
    pf[0]();//mingw ест)
    cout<<sizeof(*pf)<<endl;
    cout<< pf <<' '<<(pf+1)<<' '<<foo<<endl;//1 1 1
    return 0;
}
нормальная бредятина. Опасная к тому же. Если захочется как-то так: pf[1]();
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12938 / 6805 / 1821
Регистрация: 18.10.2014
Сообщений: 17,224
05.05.2021, 17:59
Цитата Сообщение от liv Посмотреть сообщение
При вызове функции по указателю происходит неявное разыменовывание, т.е. вызов функции по адресу из указателя.
Ну с совсем педантичной точки зрения, никакого разыменования тут не происходит и не нужно. Языку С++ не нужно "разыменовывать" указатели на функции - встроенный оператор () умеет вызывать функции сразу через указатель.

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

Добавлено через 4 минуты
Цитата Сообщение от IGPIGP Посмотреть сообщение
а адресная арифметика бессмысленна, даже если компилятор делает вид, что он чего-то складывает (или вычитает)[...]нормальная бредятина
Это не "бредятина", а булевское значение true, выведенное как 1. Оператора << для вывода адресов функций не существует, поэтому вместо него, как уже миллион раз объяснялось, используется оператор вывода bool.

Если GCC разрешает адресную арифметику для указателей на функции, то это нестандартное расширение, аналогичное адресной арифметике на void *. Не надо лишь пытаться анализировать это поведение через прямое применение <<, ибо будет 1 1 1

C++
1
2
3
4
5
6
7
8
9
#include <iostream>
 
void foo() {}
 
int main() 
{
  std::cout << &foo << " " << &foo + 1 << std::endl;
  std::cout << (void *) &foo << " " << (void *) (&foo + 1) << std::endl;
}
Code
1
2
1 1
0x400a30 0x400a31
3
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
05.05.2021, 20:07
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
то не "бредятина", а булевское значение true, выведенное как 1.
Понятно. Похожая на char * история. Вспомнил. А бредятина там все же есть. И она в том что
(void*)foo и (void*)(foo+1)
отличаются на 1. То есть, размер же не должен быть равен 1 ? А выходит, что объекта там и нет. Я знаю что функция - не объект, но фейковый размер в один байт, это не то что хочется иметь задаваясь вопросом - :"А куда же он всё-таки указывает?". Прочесть случайные данные, это не так плохо, как запустить случайный код.
И ещё: попытка взять адрес такого указателя не функции, а именно как вы сделали, - указателя:
&foo
даёт 4 байта разницы. Указатель указателя, работает нормально То есть, это на mingw так.

C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
    int foo(){ cout<<"foo!\n";}
    int main()
    {
    int (*pf)()=foo;
    pf[0]();//mingw ест)
    cout<<sizeof(*pf)<<endl;
    cout<<(void*)pf <<' '<<(void*)(pf+1) <<endl;//разница в  1
    cout<<(void*)&pf <<' '<<(void*)(&pf+1) <<endl;//разница в  4     
    return 0;
}
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12938 / 6805 / 1821
Регистрация: 18.10.2014
Сообщений: 17,224
05.05.2021, 20:21
Цитата Сообщение от IGPIGP Посмотреть сообщение
И она в том что
(void*)foo и (void*)(foo+1)
отличаются на 1.
Компилятор GCC, очевидно, реализует расширенную (неподдерживаемую языком) адресную арифметику как арифметику байтов. Это относится как к арифметике void * указателей, так и к к арифметике указателей на функции. Так им захотелось. Имеют право.

Цитата Сообщение от IGPIGP Посмотреть сообщение
И ещё: попытка взять адрес такого указателя не функции, а именно как вы сделали, - указателя:
&foo даёт 4 байта разницы.
Не понял. У меня в примере нет никакого "адрес такого указателя не функции". У меня в примере адрес берется от самой функции. Никакой разницы между foo + 1 и &foo + 1 в контексте моего примера нет. И то и другое запрещено языком. И то и другое "компилируется" лишь благодаря нестандартному расширению GCC. И то и другое реализует арифметику байтов.

А у вас в примере вы завели переменную типа "указатель на функцию" и применили к ней &. Это совсем другое. Здесь вы работаете с обычным "указателем на данные". Ничего примечательного в нем нет и ведет но себя точно так же, как и любые другие указатели на данные: размер указуемого типа 4, значит +1 сдвинет указатель на 4 байта. Все как и должно быть.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
05.05.2021, 20:26
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Никакой разницы между foo + 1 и &foo + 1 в контексте моего примера нет.
Я же написал
Цитата Сообщение от IGPIGP Посмотреть сообщение
То есть, это на mingw так.
Пример тоже дал. Там разные результаты. Пересмотрите ещё раз. В случае когда применяется взятие адреса к имени функции - получается указатель указателя. Сейчас попробую при помощи typeid разобрать. А то, что g++ работает со своими мухами, это ясно. Я об этом тоже написал.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
05.05.2021, 20:29
Цитата Сообщение от IGPIGP Посмотреть сообщение
Пример тоже дал. Там разные результаты. Пересмотрите ещё раз. В случае когда применяется взятие адреса к имени функции - получается указатель указателя.
У вас же в примере pf - это не "имя функции", а имя переменной-указателя на функцию. Это же разные вещи.
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12938 / 6805 / 1821
Регистрация: 18.10.2014
Сообщений: 17,224
05.05.2021, 20:31
Цитата Сообщение от IGPIGP Посмотреть сообщение
Пример тоже дал. Там разные результаты.
Нет, конечно. Результаты в MinGW совершенно однаковые в обоих случаях. Попробуйте сами

C++
1
2
3
4
5
6
7
8
9
10
#include <iostream>
 
void foo() {}
 
int main() 
{
  std::cout << &foo << " " << &foo + 1 << std::endl;
  std::cout << (void *) foo << " " << (void *) (foo + 1) << std::endl;
  std::cout << (void *) &foo << " " << (void *) (&foo + 1) << std::endl;
}
Цитата Сообщение от IGPIGP Посмотреть сообщение
В случае когда применяется взятие адреса к имени функции - получается указатель указателя.
Нет, конечно. Откуда вы это взяли??? Взятие адреса, примененное к имени функции всегда дает "указатель на функцию" и никогда (!) - указатель на указатель.

В вашем примере & применяется не "к имени функции", а к обычной переменной-указателю pf, которая функцией не является даже отдаленно. Отсюда и различия.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9006 / 4707 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
05.05.2021, 20:36
Да. Всё верно. Разница строго в 1 и взятие адреса &foo это то же что и foo. Что есть бредятина, также.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12938 / 6805 / 1821
Регистрация: 18.10.2014
Сообщений: 17,224
05.05.2021, 20:41
Цитата Сообщение от IGPIGP Посмотреть сообщение
и взятие адреса &foo это то же что и foo. Что есть бредятина, также.
Function type decay, т.е. автоматическое превращение значений типа "функция" в значения типа "указатель на функцию" - это явление той же природы и того же порядка, что и array type decay, т.е. автоматическое превращение значений типа "массив" в значения типа "указатель на элемент массива". Как и в случае с массивами, это происходит не во всех контекстах.

"Бредятина" или нет, таковы реалии С и С++.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
05.05.2021, 20:41
Помогаю со студенческими работами здесь

Suspicious pointer conversion in function main
возникла проблема при компиляции программы.... предупреждение Suspicious pointer conversion in function main возникло в строке...

WriteFile и ReadFile: Suspicious pointer conversion in function main
Всем привет. Знакомлюсь с WinAPI и потоками, но чет не заладилось... Ругается на WriteFile и ReadFile #include &lt;stdio.h&gt; ...

More C++ Idioms/Execute-Around Pointer как в этом случае работает "operator->()"
Читаю сейчас More C++ Idioms Дошел до Execute-Around Pointer и впал в ступор. Есть код // ideone.com/R728xo #include...

Как исправить предупреждение implicit declaration of function и incompatible integer to pointer conversion assigni
Необходимо было реализовать функцию int_vector_copy, результат который был бы указатель на копию вектора v. NULL, если не удалось выделить...

Incorrect Data Type For Operator Or @function: Text Expected
Всем привет! Есть документ созданный по форме с 3 полями: Все поля типа Number-Currency вычисляемые. Field1 формула Field2+Field3 ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru