Ответ 1
Что делает эта программа?
main(_){write(read(0,&_,1)&&main());}
Прежде чем мы проанализируем это, пусть префикс:
main(_) {
write ( read(0, &_, 1) && main() );
}
Во-первых, вы должны знать, что _
является допустимым именем переменной, хотя и уродливым. Позвольте изменить его:
main(argc) {
write( read(0, &argc, 1) && main() );
}
Далее, поймите, что тип возврата функции и тип параметра являются необязательными в C (но не в С++):
int main(int argc) {
write( read(0, &argc, 1) && main() );
}
Далее, понять, как работают возвращаемые значения. Для некоторых типов ЦП возвращаемое значение всегда сохраняется в одних и тех же регистрах (например, EAX на x86). Таким образом, если вы опускаете оператор return
, возвращаемое значение, скорее всего, будет тем, что возвращает самая последняя функция.
int main(int argc) {
int result = write( read(0, &argc, 1) && main() );
return result;
}
Вызов read
более или менее очевидный: он читает из стандартного в (дескриптор файла 0) в память, расположенную в &argc
, для 1
байта. Он возвращает 1
, если чтение было успешным, и 0 в противном случае.
&&
является логическим оператором "и". Он оценивает свою правую сторону тогда и только тогда, когда левая сторона "истинна" (технически, любое ненулевое значение). Результатом выражения &&
является int
, который всегда равен 1 (для "true" ) или 0 (для false).
В этом случае правая сторона вызывает main
без аргументов. Вызов main
без аргументов после объявления его 1 аргументом - это поведение undefined. Тем не менее, он часто работает, если вы не заботитесь об исходном значении параметра argc
.
Результат &&
затем передается в write()
. Итак, наш код теперь выглядит так:
int main(int argc) {
int read_result = read(0, &argc, 1) && main();
int result = write(read_result);
return result;
}
Хм. Быстрый просмотр страниц руководства показывает, что write
принимает три аргумента, а не один. Другой случай поведения undefined. Точно так же, как вызов main
с слишком небольшим количеством аргументов, мы не можем предсказать, что получит write
для своих 2-го и 3-го аргументов. На типичных компьютерах они получат что-то, но мы не можем точно знать, что. (На нетипичных компьютерах могут случиться странные вещи.) Автор полагается на write
на получение того, что ранее было сохранено в стеке памяти. И он полагается на то, что это 2-й и 3-й аргументы для чтения.
int main(int argc) {
int read_result = read(0, &argc, 1) && main();
int result = write(read_result, &argc, 1);
return result;
}
Фиксируя недействительный вызов main
, добавляя заголовки и расширяя &&
, мы имеем:
#include <unistd.h>
int main(int argc, int argv) {
int result;
result = read(0, &argc, 1);
if(result) result = main(argc, argv);
result = write(result, &argc, 1);
return result;
}
Выводы
Эта программа не будет работать так, как ожидалось, на многих компьютерах. Даже если вы используете тот же компьютер, что и оригинальный автор, он может не работать в другой операционной системе. Даже если вы используете тот же компьютер и ту же операционную систему, он не будет работать на многих компиляторах. Даже если вы используете один и тот же компилятор и операционную систему компьютера, это может не сработать, если вы измените флаги командной строки компилятора.
Как я уже сказал в комментариях, вопрос не имеет верного ответа. Если вы нашли организатора конкурса или судьи конкурса, который говорит иначе, не приглашайте их на следующий конкурс.