Antes de entrar no cerne da questão sobre o que está acontecendo, é importante apontar que o programa está malformado de acordo com relatório de defeito 1886: Language linkage for main () :
[...] Um programa que declara uma variável main no escopo global ou que declara o nome main com a ligação da linguagem C (em qualquer namespace) está mal formado. [...]
As versões mais recentes do clang e do gcc tornam isso um erro e o programa não compila ( consulte o exemplo ao vivo do gcc ):
error: cannot declare '::main' to be a global variable
int main = ( std::cout << "C++ is excellent!\n", 195 );
^
Então, por que não havia diagnóstico nas versões mais antigas do gcc e do clang? Esse relatório de defeito nem tinha uma proposta de resolução até o final de 2014 e, portanto, esse caso só foi explicitamente malformado muito recentemente, o que requer um diagnóstico.
Antes disso, parece que isso seria um comportamento indefinido, uma vez que estão a violar um deve exigência do projeto de C ++ padrão da seção 3.6.1
[basic.start.main] :
Um programa deve conter uma função global chamada main, que é o início designado do programa. [...]
O comportamento indefinido é imprevisível e não requer um diagnóstico. A inconsistência que vemos ao reproduzir o comportamento é um comportamento indefinido típico.
Então, o que o código está realmente fazendo e por que, em alguns casos, ele produz resultados? Vamos ver o que temos:
declarator
| initializer----------------------------------
| | |
v v v
int main = ( std::cout << "C++ is excellent!\n", 195 );
^ ^ ^
| | |
| | comma operator
| primary expression
global variable of type int
Temos main
que é um int declarado no namespace global e está sendo inicializado, a variável tem duração de armazenamento estático. É definido pela implementação se a inicialização ocorrerá antes que uma tentativa de chamada main
seja feita, mas parece que o gcc faz isso antes de chamar main
.
O código usa o operador vírgula , o operando esquerdo é uma expressão de valor descartada e é usado aqui apenas para o efeito colateral da chamada std::cout
. O resultado do operador vírgula é o operando correto que, neste caso, é o prvalue 195
atribuído à variável main
.
Podemos ver que sergej aponta a montagem gerada mostra que cout
é chamada durante a inicialização estática. Embora o ponto mais interessante para discussão, consulte a sessão do godbolt ao vivo seria este:
main:
.zero 4
e o subsequente:
movl $195, main(%rip)
O cenário provável é que o programa salte para o símbolo main
esperando que o código válido esteja lá e, em alguns casos, apresentará falha de seg . Portanto, se for esse o caso, esperaríamos que armazenar código de máquina válido na variável main
pudesse levar a um programa viável , supondo que estejamos localizados em um segmento que permite a execução do código. Podemos ver que esta entrada do IOCCC de 1984 faz exatamente isso .
Parece que podemos fazer o gcc fazer isso em C usando ( veja ao vivo ):
const int main = 195 ;
Ele falha se a variável main
não for const presumivelmente porque não está localizada em um local executável, Hat Dica para este comentário aqui que me deu essa idéia.
Veja também a resposta FUZxxl aqui para uma versão C específica desta pergunta.