Значение int (*) (int *) = 5 (или любое целочисленное значение)

Я не могу понять это:

int main() {
    int (*) (int *) = 5;
    return 0;
}

Вышеприведенное присваивание компилируется с помощью g++ С++ 11. Я знаю, что int (*) (int *) является указателем на функцию, которая принимает аргумент (int *) as и возвращает int, но я не понимаю, как вы могли бы приравнять его к 5. Сначала я думал, что это функция, которая постоянно возвращает 5 (из моего недавнего обучения в F #, вероятно, ха-ха), тогда я кратко подумал, что указатель функции указывает на ячейку памяти 5, но это не работает, очевидно, и не имеет шестнадцатеричных значений.

Подумав, что это может быть потому, что функция возвращает int, и что назначение int в порядке (как-то), я также пробовал это:

int * (*) (int *) = my_ptr

где my_ptr имеет тип int *, тот же тип, что и этот второй указатель функции, как в первом случае с типом int. Это не компилируется. Назначение 5 или любого значения int вместо my_ptr не компилируется для этого указателя функции.

Итак, что означает назначение?

Обновление 1

У нас есть подтверждение, что это ошибка, как показано в лучшем ответе. Однако до сих пор неизвестно, что на самом деле происходит со значением, которое вы назначаете указателю функции, или тем, что происходит с назначением. Любые (хорошие) объяснения по этому поводу будут очень оценены! Пожалуйста, ознакомьтесь с приведенными ниже изменениями, чтобы узнать больше о проблеме.

Изменить 1

Я использую gcc версии 4.8.2 (в Ubuntu 4.8.2)

Изменить 2

Собственно, приравнивание к чему-либо работает на моем компиляторе. Даже приравнивая его к переменной std::string или имени функции, которая возвращает double, работает.

Изменить 2.1

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

std::string (*) () = 5.6;

Но как только указатель функции будет работать с функцией, возвращающей некоторый указатель, он не компилируется, например, с помощью

some_data_type ** (*) () = any_value;

Ответ 1

Это ошибка в g++.

 int (*) (int *) 

- это имя типа.

В С++ вы не можете иметь объявление с именем типа без идентификатора.

Итак, это скомпилируется с g++.

 int (*) (int *) = 5;

и это тоже компилируется:

 int (*) (int *);

но они являются недопустимыми объявлениями.

ИЗМЕНИТЬ:

TC упоминает в комментариях ошибку bugzilla 60680 с аналогичным тестовый пример , но он еще не утвержден. Ошибка подтверждена в bugzilla.

EDIT2

Когда два объявления выше находятся в области файлов, g++ корректно выдает диагностику (она не может выдавать диагностику в области блока).

EDIT3

Я проверил, и я могу воспроизвести проблему в последней версии g++ версии 4 (4.9.2), последней предварительной версии версии 5 (5.0.1 20150412) и последней экспериментальной версии 6 (6.0.0 20150412).

Ответ 2

Недействительно С++. Помните, что из-за того, что ваш компилятор компилируется, он не делает его действительным. У компиляторов, как и у всего сложного программного обеспечения, иногда есть ошибки, и это похоже на одно.

В отличие от clang++ жалуется:

funnycast.cpp:3:11: error: expected expression
    int (*) (int *) = 5;
          ^
funnycast.cpp:3:18: error: expected '(' for function-style cast or type construction
    int (*) (int *) = 5;
             ~~~ ^
funnycast.cpp:3:19: error: expected expression
    int (*) (int *) = 5;
                  ^
3 errors generated.

Это ожидаемое поведение, потому что строка нарушения недействительна С++. Он предназначен для назначения (из-за =), но не содержит идентификатора.

Ответ 3

Как указывали другие ответы, это ошибка, которая

int (*) (int *) = 5;

компилирует. Разумное приближение этого утверждения, которое, как ожидается, будет иметь смысл:

int (*proc)(int*) = (int (*)(int*))(5);

Теперь proc является указателем на функцию, который ожидает, что адрес 5 будет базовым адресом функции, которая принимает int* и возвращает int.

На некоторых микроконтроллерах/микропроцессорах 5 может быть допустимый адрес кода, и там может быть возможно найти такую ​​функцию.

На большинстве компьютеров общего назначения первая страница памяти (адреса 0-1023 для страниц 4 КБ) явно недействительна (не отображается), чтобы улавливать обращения null.

Таким образом, хотя поведение зависит от платформы, можно разумно ожидать возникновения ошибки страницы при вызове *proc (например, (*proc)(&v)). До того момента, когда вызывается *proc, ничего необычного не происходит.

Если вы не пишете динамический компоновщик, вы почти наверняка не должны численно вычислять адреса и назначать их переменным-указателю на функцию.

Ответ 4

/usr/lib/gcc/x86_64-pc-cygwin/4.9.2/cc1plus.exe -da so.cpp

Эта командная строка генерирует много промежуточных файлов. Первый из них, so.cpp.170r.expand, говорит:

...
int main() ()
{
  int D.2229;
  int _1;

;;   basic block 2, loop depth 0
;;    pred:       ENTRY
  _1 = 0;
;;    succ:       3

;;   basic block 3, loop depth 0
;;    pred:       2
<L0>:
  return _1;
;;    succ:       EXIT

}
...

Это все равно не отвечает на то, что происходит точно, но это должен быть шаг в правильном направлении.