Date: 28.01.2018 14:08:48
Есть легкий способ наглядно продемонстрировать отличие. Переключитесь в режим С++, создайте две функции с 1 и 2 вариантом сигнатуры, и попробуйте вызвать с левым типом аргумента (ну int скажем). Тогда будет ошибка компиляции "неоднозначный вызов перегруженной функции", в сообщении которой будет видно, чем отличаются записи с точки зрения компилятора.
Во одном случае * не только "прилипла" к void, но и "раздвоилась".
Date: 28.01.2018 15:54:43
"На мой взгляд, неправильно считать сообщения компилятора С++ эталоном для языка С."
Та что вы, какой эталон. Я это просто предложил это, как способ наглядной демонстрации. Понятно, что языки разные, и поведение в них не обязано быть согласованным; но в плане обработки списков параметров функции оно обычно все же согласовано.
Date: 28.01.2018 17:16:16
Не знаю ;) Хороший вопрос, но чтобы ответить на него, нужно долго копаться в стандартах, что не очень увлекательное занятие. Если чисто интуитивно, то логика компилятора выглядит как-то так:
void func(void (*_f(void))); //скобки не играют роли, пропускаем
void func(void *_f(void)); //звездочка прилипает к void, по принципу наиболее длинного токена
void func((void *) _f(void)); //для получения валидного типа добавляем вторую звездочку
void func((void *) * _f(void)); //итоговый тип получаем вот такой
Опять же, если поведение одинаково в разных компиляторах, с высокой вероятностью это не баг.
Что касается мусора при вызове без параметров, возможно, это какое-то наследие традиционного Си, что если нет прототипа, подразумевается что у функции нет параметров. Чтобы не было таких проблем, лучше всегда писать прототип.
Date: 30.01.2018 3:09:40
Автор: VadimTagil