Trước khi đi sâu vào phần nội dung của câu hỏi về những gì đang xảy ra, điều quan trọng là phải chỉ ra rằng chương trình đó không hợp lệ theo báo cáo lỗi 1886: Liên kết ngôn ngữ cho main () :
[...] Một chương trình khai báo một biến chính ở phạm vi toàn cục hoặc khai báo tên chính với liên kết ngôn ngữ C (trong bất kỳ không gian tên nào) là không đúng. [...]
Các phiên bản mới nhất của clang và gcc gây ra lỗi này và chương trình sẽ không biên dịch ( xem ví dụ trực tiếp về gcc ):
error: cannot declare '::main' to be a global variable
int main = ( std::cout << "C++ is excellent!\n", 195 );
^
Vậy tại sao không có chẩn đoán trong các phiên bản cũ hơn của gcc và clang? Báo cáo khiếm khuyết này thậm chí không có giải pháp được đề xuất cho đến cuối năm 2014 và vì vậy trường hợp này chỉ mới được hình thành rõ ràng gần đây, cần được chẩn đoán.
Trước đó, có vẻ như đây sẽ là hành vi không xác định vì chúng tôi đang vi phạm yêu cầu phải có của tiêu chuẩn C ++ dự thảo từ phần 3.6.1
[basic.start.main] :
Một chương trình phải chứa một hàm toàn cục được gọi là hàm chính, là hàm khởi động được chỉ định của chương trình. [...]
Hành vi không xác định là không thể đoán trước và không cần chẩn đoán. Sự không nhất quán mà chúng ta thấy khi tái tạo hành vi là hành vi không xác định điển hình.
Vì vậy, mã thực sự đang làm gì và tại sao trong một số trường hợp, nó tạo ra kết quả? Hãy xem những gì chúng tôi có:
declarator
| initializer----------------------------------
| | |
v v v
int main = ( std::cout << "C++ is excellent!\n", 195 );
^ ^ ^
| | |
| | comma operator
| primary expression
global variable of type int
Chúng ta có main
một int được khai báo trong không gian tên chung và đang được khởi tạo, biến có thời lượng lưu trữ tĩnh. Việc thực thi được xác định liệu quá trình khởi tạo có diễn ra trước khi thực hiện một cuộc gọi hay không main
nhưng có vẻ như gcc thực hiện điều này trước khi gọi main
.
Đoạn mã sử dụng toán tử dấu phẩy , toán hạng bên trái là một biểu thức giá trị bị loại bỏ và được sử dụng ở đây chỉ cho tác dụng phụ của việc gọi std::cout
. Kết quả của toán tử dấu phẩy là toán hạng bên phải, trong trường hợp này là giá trị prvalue 195
được gán cho biến main
.
Chúng ta có thể thấy sergej chỉ ra các chương trình lắp ráp được tạo ra cout
được gọi trong quá trình khởi tạo tĩnh. Mặc dù điểm thú vị hơn để thảo luận, hãy xem phiên hỗ trợ trực tiếp sẽ là:
main:
.zero 4
và tiếp theo:
movl $195, main(%rip)
Tình huống có thể xảy ra là chương trình nhảy đến biểu tượng main
mong đợi mã hợp lệ ở đó và trong một số trường hợp sẽ xảy ra lỗi . Vì vậy, nếu trường hợp đó xảy ra, chúng tôi mong đợi việc lưu trữ mã máy hợp lệ trong biến main
có thể dẫn đến chương trình khả thi , giả sử chúng tôi đang ở trong một phân đoạn cho phép thực thi mã. Chúng ta có thể thấy mục IOCCC 1984 này làm được điều đó .
Có vẻ như chúng ta có thể sử dụng gcc để thực hiện việc này trong C ( xem trực tiếp ):
const int main = 195 ;
Sẽ xảy ra lỗi nếu biến main
có lẽ không phải là const vì nó không được đặt ở vị trí thực thi, Hat Mẹo cho nhận xét này ở đây đã cho tôi ý tưởng này.
Cũng xem câu trả lời FUZxxl tại đây cho phiên bản C cụ thể của câu hỏi này.