Ответ 1
Никогда не пишите такой код.
Для j<1000
, j/1000
равно нулю (целочисленное деление). Итак:
(&main + (&exit - &main)*(j/1000))(j+1);
эквивалентно:
(&main + (&exit - &main)*0)(j+1);
Что есть:
(&main)(j+1);
Что вызывает main
с j+1
.
Если j == 1000
, то те же строки выводятся как:
(&main + (&exit - &main)*1)(j+1);
Что сводится к
(&exit)(j+1);
Это exit(j+1)
и покидает программу.
(&exit)(j+1)
и exit(j+1)
- это в основном одно и то же: цитирование C99 §6.3.2.1/4:
Обозначение функции - это выражение, имеющее тип функции. За исключением случаев, когда операнд оператора sizeof или унарный и оператор, обозначение функции с тип " возвращаемый тип функции" преобразуется в выражение, которое имеет тип " указатель на функция возвращающего типа".
exit
является обозначением функции. Даже без унарного оператора &
address, он рассматривается как указатель на функцию. (&
просто делает его явным.)
И вызовы функций описаны в п. 6.5.2.2/1 и следующие:
Выражение, обозначающее вызываемую функцию, должно иметь тип указатель на функцию, возвращающий void или возвращающий тип объекта, отличный от типа массива.
Итак, exit(j+1)
работает из-за автоматического преобразования типа функции в тип указателя на функцию, а (&exit)(j+1)
работает также с явным преобразованием в тип указателя на функцию.
При этом вышеуказанный код не соответствует (main
принимает либо два аргумента, либо вообще ничего), и &exit - &main
, я полагаю, undefined в соответствии с § 6.5.5/9:
Когда два указателя вычитаются, оба должны указывать на элементы одного и того же объекта массива или один за последним элементом объекта массива;...
Добавление (&main + ...)
было бы само по себе и могло бы использоваться, если добавленная величина была равна нулю, поскольку в § 6.5.6/7 говорится:
Для этих операторов указатель на объект, который не является элементом массив ведет себя так же, как указатель на первый элемент массива длиной один с тип объекта как его тип элемента.
Таким образом, добавление нуля в &main
будет нормально (но не очень полезно).