如何一个程序与一个全局变量称为main而不是一个主要的函数工作? [英] How can a program with a global variable called main instead of a main function work?

查看:1372
本文介绍了如何一个程序与一个全局变量称为main而不是一个主要的函数工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下计划:

  #include< iostream> 
int main =(std :: cout<<C ++ is excellent!\\\
,195);

在Windows 7操作系统上使用g ++ 4.8.1(mingw64),程序编译并运行良好,打印:


C ++非常好!


到控制台。 main 似乎是一个全局变量而不是一个函数;这个程序如何执行没有函数 main()?此代码是否符合C ++标准?程序的行为是否明确定义?我还使用了 -pedantic-errors 选项,但是程序仍然编译并运行。

解决方案

在讨论关于正在发生的事情的问题之前,重要的是要指出,根据缺陷报告1886:main()的语言链接形成,


[...]在全局范围声明一个变量main或者声明名为main的程序语言链接(在任何命名空间中)是不成形的。 [...]


clang和gcc的最新版本使得这是一个错误, see gcc live example ):

 错误:无法将':: main'声明为全局变量
int main =(std :: cout< n,195);
^

那么,为什么在旧版本的gcc和clang中没有诊断?这个缺陷报告甚至在2014年年底之前没有提议的解决方案,因此这个病例最近才显示错误,需要诊断。



在此之前,看起来这是不确定的行为,因为我们违反了 c 条款草案C ++标准的要求 3.6.1 .start.main] :


程序应包含一个名为main的全局函数, 。 [...]


未定义的行为是不可预测的,不需要诊断。我们看到的再现行为的不一致是典型的未定义的行为。



那么,代码实际上是什么,为什么在某些情况下会产生结果呢?让我们看看我们有什么:

 声明者
| initializer ----------------------------------
| | |
v v v
int main =(std :: cout<<C ++ is excellent!\\\
,195);
^ ^ ^
| | |
| |逗号运算符
|主表达式
类型为int的全局变量

我们有 main 这是在全局命名空间中声明并正在初始化的 int ,该变量具有静态存储持续时间。它是实现定义是否初始化将在尝试调用 main 之前发生,但它看起来gcc在调用 main



代码使用逗号运算符,左操作数为一个废弃的值表达式,并且在这里仅用于调用 std :: cout 的副作用。逗号运算符的结果是右操作数,在这种情况下是赋值给变量 main 的prvalue 195 >。



我们可以看到 sergej指出生成的程序集显示在静态初始化期间调用 cout 。尽管更有趣的讨论点查看live godbolt会话将是:

  main:
。zero 4

和后续:

  movl $ 195,main(%rip)
/ pre>

可能的情况是程序跳转到符号 main ,期望有效的代码在那里, 某些情况会出现故障。因此,如果是这种情况,我们期望将有效的机器代码存储在变量 main 中可能导致可行程序,假设我们位于段允许代码执行。我们可以查看这个1984 IOCCC条目是否只是那个



看来我们可以得到gcc在C ( 查看实时 ):

  const int main = 195; 

如果变量 main 不是const可能是因为它不位于可执行位置,提示此



另请参阅 FUZxxl在这里回答到此问题的C特定版本。


Consider following program:

#include <iostream>
int main = ( std::cout << "C++ is excellent!\n", 195 ); 

Using g++ 4.8.1 (mingw64) on Windows 7 OS, the program compiles and runs fine, printing:

C++ is excellent!

to the console. main appears to be a global variable rather than a function; how can this program execute without the function main()? Does this code conform to the C++ standard? Is the behavior of the program is well defined? I have also used the -pedantic-errors option but the program still compiles and runs.

解决方案

Before going into the meat of the question about what is going on, it is important to point out that program is ill-formed as per defect report 1886: Language linkage for main():

[...] A program that declares a variable main at global scope or that declares the name main with C language linkage (in any namespace) is ill-formed. [...]

The most recent versions of clang and gcc makes this an error and the program will not compile (see gcc live example):

error: cannot declare '::main' to be a global variable
int main = ( std::cout << "C++ is excellent!\n", 195 ); 
    ^

So why was there no diagnostic in older versions of gcc and clang? This defect report did not even have a proposed resolution until late 2014 and so this case was only very recently explicitly ill-formed, which requires a diagnostic.

Prior to this, it seems like this would be undefined behavior since we are violating a shall requirement of the draft C++ standard from section 3.6.1 [basic.start.main]:

A program shall contain a global function called main, which is the designated start of the program. [...]

Undefined behavior is unpredictable and does not require a diagnostic. The inconsistency we see with reproducing the behavior is typical undefined behavior.

So what is the code actually doing and why in some cases does it produce results? Let's see what we have:

declarator  
|        initializer----------------------------------
|        |                                           |
v        v                                           v
int main = ( std::cout << "C++ is excellent!\n", 195 ); 
    ^      ^                                   ^
    |      |                                   |
    |      |                                   comma operator
    |      primary expression
global variable of type int

We have main which is an int declared in the global namespace and is being initialized, the variable has static storage duration. It is implementation defined whether the initialization will take place before an attempt to call main is made but it appears gcc does do this before calling main.

The code uses the comma operator, the left operand is a discarded value expression and is used here solely for the side effect of calling std::cout. The result of the comma operator is the right operand which in this case is the prvalue 195 which is assigned to the variable main.

We can see sergej points out the generated assembly shows that cout is called during static initialization. Although the more interesting point for discussion see live godbolt session would be this:

main:
.zero   4

and the subsequent:

movl    $195, main(%rip)

The likely scenario is that the program jumps to the symbol main expecting valid code to be there and in some cases will seg-fault. So if that is the case we would expect storing valid machine code in the variable main could lead to workable program, assuming we are located in a segment that allows code execution. We can see this 1984 IOCCC entry does just that.

It appears we can get gcc to do this in C using (see it live):

const int main = 195 ;

It seg-faults if the variable main is not const presumably because it is not located in an executable location, Hat Tip to this comment here which gave me this idea.

Also see FUZxxl answer here to a C specific version of this question.

这篇关于如何一个程序与一个全局变量称为main而不是一个主要的函数工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆