Никогда не пишите такой код.
Для 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-of он обрабатывается как указатель на функцию. (&
просто делает это явным.)
А вызовы функций описаны в §6.5.2.2 / 1 и далее:
Выражение, которое обозначает вызываемую функцию, должно иметь тип указатель на функцию , возвращающий void или возвращающий тип объекта, отличный от типа массива.
Так что exit(j+1)
работает из-за автоматического преобразования типа функции в тип указателя на функцию, а (&exit)(j+1)
работает также с явным преобразованием в тип указателя на функцию.
При этом вышеприведенный код не соответствует (main
принимает либо два аргумента, либо ни одного вообще), а &exit - &main
, я полагаю, не определен согласно §6.5.6 / 9:
Когда вычитаются два указателя, оба должны указывать на элементы одного и того же объекта массива , или один за последним элементом объекта массива; ...
Добавление (&main + ...)
было бы действительным само по себе и могло бы использоваться, , если добавленное количество было равно нулю, поскольку §6.5.6 / 7 гласит:
Для целей этих операторов указатель на объект, который не является элементом
массив ведет себя так же, как указатель на первый элемент массива длиной один с
тип объекта как тип элемента.
Так что добавление нуля к &main
будет в порядке (но не очень полезно).