무슨 일이 일어나고 있는지에 대한 질문으로 들어가기 전에 결함 보고서 1886 : Language linkage for main ()에 따라 프로그램이 잘못 구성되었음을 지적하는 것이 중요합니다 .
[...] 전역 범위에서 변수 main을 선언하거나 모든 네임 스페이스에서 C 언어 연결로 main이라는 이름을 선언하는 프로그램은 형식이 잘못되었습니다. [...]
최신 버전의 clang 및 gcc는이를 오류로 만들고 프로그램이 컴파일되지 않습니다 ( gcc 라이브 예제 참조 ).
error: cannot declare '::main' to be a global variable
int main = ( std::cout << "C++ is excellent!\n", 195 );
^
그렇다면 왜 이전 버전의 gcc 및 clang에는 진단이 없었습니까? 이 결함 보고서에는 2014 년 말까지 제안 된 해결 방법이 없었기 때문에이 사례는 최근에야 명시 적으로 잘못 구성되어 진단이 필요했습니다.
이전에는 [basic.start.main] 섹션의 C ++ 표준 초안 의 shall 요구 사항을 위반하고 있으므로 정의되지 않은 동작 인 것 같습니다 .3.6.1
프로그램은 프로그램의 지정된 시작 인 main이라는 전역 함수를 포함해야합니다. [...]
정의되지 않은 동작은 예측할 수 없으며 진단이 필요하지 않습니다. 행동을 재현 할 때 나타나는 불일치는 일반적인 정의되지 않은 행동입니다.
그렇다면 코드는 실제로 무엇을하고 있으며 어떤 경우에는 왜 결과를 생성합니까? 우리가 가진 것을 보자 :
declarator
| initializer----------------------------------
| | |
v v v
int main = ( std::cout << "C++ is excellent!\n", 195 );
^ ^ ^
| | |
| | comma operator
| primary expression
global variable of type int
우리는이 main
인 INT 전역 네임 스페이스에 선언 및 초기화되고, 변수는 정적 저장 기간을 가지고 있습니다. 호출 시도가 이루어지기 전에 초기화가 발생할지 여부는 구현에 정의 main
되어 있지만 gcc가 호출하기 전에이를 수행하는 것으로 보입니다 main
.
코드는 쉼표 연산자 를 사용하고 왼쪽 피연산자는 폐기 된 값 표현식이며 여기서는 호출의 부작용에만 사용됩니다 std::cout
. 쉼표 연산자의 결과는이 경우 195
변수에 할당 된 prvalue 인 오른쪽 피연산자입니다 main
.
sergejcout
가 정적 초기화 중에 호출되는 생성 된 어셈블리 쇼를 지적하는 것을 볼 수 있습니다 . 토론에 대한 더 흥미로운 점 은 라이브 godbolt 세션을 참조하십시오 .
main:
.zero 4
그리고 후속 :
movl $195, main(%rip)
가능한 시나리오는 프로그램이 main
유효한 코드가있을 것으로 예상 하는 기호로 점프 하고 경우에 따라 seg-fault 합니다. 따라서이 경우 유효한 기계어 코드를 변수에 저장 하면 코드 실행을 허용하는 세그먼트에 있다고 가정 main
하고 실행 가능한 프로그램으로 이어질 수 있습니다. 우리는 볼 수 있습니다 이 1984 IOCCC 항목이 수행 그냥 .
우리가 GCC가 (사용하여 C에서이 일을 얻을 수 있습니다 나타납니다 살고 볼 ) :
const int main = 195 ;
main
실행 가능한 위치에 있지 않기 때문에 아마도 변수 가 const가 아닌 경우 seg-faults , Hat Tip은 여기 에이 아이디어를 제공했습니다.
이 질문의 C 특정 버전에 대한 FUZxxl 답변 도 참조하십시오 .