Рассмотрим следующую программу C:
int f() { return 9; }
int main() {
int (*h1)(int);
h1 = f; // why is this allowed?
return h1(7);
}
В соответствии со стандартом C11, п. 6.5.16.1, в простом назначении, "одно из следующего будет выполнено", и единственное релевантное в списке следующее:
левый операнд имеет атомный, квалифицированный или неквалифицированный тип указателя и (учитывая тип, который будет иметь левый операнд после преобразования lvalue), оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов и тип, на который указывает left имеет все квалификаторы типа, на который указывает справа;
Кроме того, это "ограничение", то есть соответствующая реализация должна сообщать диагностическое сообщение, если оно нарушено.
Мне кажется, что это ограничение нарушается при назначении в программе выше. Обе стороны назначения - указатели на функции. Итак, вопрос в том, совместимы ли два типа функций? На это дан ответ в разд. 6.7.6.3:
Для двух типов функций, которые должны быть совместимыми, оба должны указывать совместимые типы возврата .146) Кроме того, списки типов параметров, если они оба присутствуют, должны согласовывать количество параметров и использование терминатора с многоточием; соответствующие параметры должны иметь совместимые типы. Если один тип имеет список типов параметров, а другой тип указан декларатором функции, который не является частью определения функции и содержит пустой список идентификаторов, список параметров не должен иметь терминатор с многоточием, а тип каждого параметра должен быть совместимым с типом, который возникает в результате применения рекламных акций по умолчанию. Если один тип имеет список типов параметров, а другой тип определяется определением функции, которое содержит (возможно, пустой) список идентификаторов, оба должны согласовывать количество параметров, а тип каждого параметра прототипа должен быть совместим с типом что является результатом применения промо-аргументов по умолчанию к типу соответствующего идентификатора.
В этом случае один из типов, тип h1, имеет список типов параметров; другой, f, нет. Следовательно, последнее предложение в приведенной выше цитате применимо: в частности, "оба согласуются по числу параметров". Ясно, что h1 принимает один параметр. Как насчет f? Следующий пункт происходит непосредственно перед вышесказанным:
Пустой список в объявлении функции, который является частью определения этой функции, указывает, что функция не имеет параметров.
Таким образом, f принимает 0 параметров. Таким образом, два типа не согласуются с количеством параметров, два типа функций несовместимы, а назначение нарушает ограничение, и должна быть выдана диагностика.
Однако при компиляции программы оба gcc 4.8 и Clang не выдают никаких предупреждений:
tmp$ gcc-mp-4.8 -std=c11 -Wall tmp4.c
tmp$ cc -std=c11 -Wall tmp4.c
tmp$
Кстати, оба компилятора выдают предупреждения, если f объявлен "int f (void)...", но это не обязательно для моего чтения стандартного выше.
Вопросы:
Q1: Назначение "h1 = f;" в программе выше нарушают ограничение "оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов"? В частности:
Q2: Тип h1 в выражении "h1 = f" является указателем на T1 для некоторого типа функции T1. Что такое T1?
Q3: Тип f в выражении "h1 = f" является указателем на T2 для некоторого типа функции T2. Что такое T2?
Q4: Существуют ли совместимые с T1 и T2 типы? (Пожалуйста, укажите соответствующие разделы Стандарта или других документов для поддержки ответа.)
Q1 ', Q2', Q3 ', Q4': Теперь предположим, что объявление f изменяется на "int f (void) {return 9;}". Ответьте на вопросы 1-4 снова для этой программы.