Chương trình này làm gì?
main(_){write(read(0,&_,1)&&main());}
Trước khi chúng ta phân tích nó, chúng ta hãy tô điểm nó:
main(_) {
write (read(0, &_, 1) && main());
}
Trước tiên, bạn nên biết rằng _
là một tên biến hợp lệ, mặc dù là một xấu xí.Hãy thay đổi nó:
main(argc) {
write(read(0, &argc, 1) && main());
}
Tiếp theo, nhận ra rằng kiểu trả về của một hàm, và loại một tham số là tùy chọn trong C (nhưng không phải trong C++):
int main(int argc) {
write(read(0, &argc, 1) && main());
}
Tiếp theo, hiểu như thế nào giá trị trả về hoạt động. Đối với một số loại CPU nhất định, giá trị trả về luôn được lưu trữ trong cùng sổ đăng ký (ví dụ: EAX trên x86). Do đó, nếu bạn bỏ qua câu lệnh return
, giá trị trả lại là có khả năng sẽ trở thành chức năng mới nhất được trả lại.
int main(int argc) {
int result = write(read(0, &argc, 1) && main());
return result;
}
Các cuộc gọi đến read
là nhiều hay ít rõ ràng: nó đọc từ tiêu chuẩn trong (file descriptor 0), vào bộ nhớ nằm ở &argc
, cho 1
byte. Nó trả về 1
nếu đọc thành công và 0 ngược lại.
&&
là toán tử logic "và". Nó đánh giá phía bên tay phải của nó nếu và chỉ khi nó nằm bên trái là "true" (về mặt kỹ thuật, bất kỳ giá trị khác 0). Kết quả của biểu thức &&
là int
luôn là 1 (cho "true") hoặc 0 (đối với false).
Trong trường hợp này, phía bên tay phải gọi main
không có đối số. Gọi main
không có đối số sau khi khai báo nó với 1 đối số là hành vi không xác định. Tuy nhiên, nó thường hoạt động, miễn là bạn không quan tâm đến giá trị ban đầu của tham số argc
.
Kết quả của số &&
sau đó được chuyển đến write()
. Vì vậy, mã của chúng tôi bây giờ trông giống như:
int main(int argc) {
int read_result = read(0, &argc, 1) && main();
int result = write(read_result);
return result;
}
Hmm. Xem nhanh các trang hướng dẫn cho thấy rằng write
có ba đối số chứ không phải một đối số. Một trường hợp khác của hành vi không xác định. Cũng giống như gọi main
với quá ít đối số, chúng tôi không thể dự đoán những gì write
sẽ nhận được đối số thứ 2 và thứ 3 của nó. Trên máy tính thông thường, họ sẽ nhận được một cái gì đó, nhưng chúng tôi không thể biết chắc chắn những gì. (Trên các máy tính không điển hình, những điều kỳ lạ có thể xảy ra.) Tác giả dựa trên write
nhận bất kỳ thứ gì trước đây được lưu trữ trên ngăn xếp bộ nhớ. Và, anh ta dựa vào rằng là đối số thứ 2 và thứ 3 để đọc.
int main(int argc) {
int read_result = read(0, &argc, 1) && main();
int result = write(read_result, &argc, 1);
return result;
}
Sửa cuộc gọi không hợp lệ để main
, và thêm tiêu đề, và mở rộng &&
ta có:
#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;
}
Kết luận
Chương trình này sẽ không hoạt động như mong đợi trên nhiều máy tính. Ngay cả khi bạn sử dụng cùng một máy tính với tư cách là tác giả gốc, nó có thể không hoạt động trên một hệ điều hành khác. Ngay cả khi bạn sử dụng cùng một máy tính và cùng một hệ điều hành, nó sẽ không hoạt động trên nhiều trình biên dịch. Ngay cả khi bạn sử dụng cùng một trình biên dịch máy tính và hệ điều hành, nó có thể không hoạt động nếu bạn thay đổi cờ dòng lệnh của trình biên dịch.
Như tôi đã nói trong phần nhận xét, câu hỏi không có câu trả lời hợp lệ.Nếu bạn tìm thấy người tổ chức cuộc thi hoặc thẩm phán cuộc thi nói cách khác, đừng mời họ tham gia cuộc thi tiếp theo của bạn.
Chương trình đó sẽ không biên dịch trong C++. Đang xóa thẻ C++. –
@ Robᵩ Ah cảm ơn bạn. Tôi đã bất cẩn. – RaunakS
Ngay cả trong C, chương trình đó gọi hành vi không xác định theo nhiều cách. Kết quả là có thể dự đoán chỉ cho các trình biên dịch cụ thể nhắm mục tiêu các loại CPU cụ thể (ngay cả trên codegolf, chương trình này chỉ làm điều gì đó thú vị ở mức tối ưu hóa cụ thể). Câu trả lời đúng cho "Chương trình này làm gì?" bao gồm "Nó phụ thuộc", "Bất cứ điều gì nó muốn," và "Nó khiến bạn bị sa thải." –