如何在C main()方法的工作? [英] How does the main() method work in C?

查看:107
本文介绍了如何在C main()方法的工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道有两种不同的签名写的主要方法 -

I know there are two different signatures to write the main method -

int main()
{
   //Code
}

或处理命令行参数,我们把它写成 -

or for handling command line argument, we write it as-

int main(int argc, char * argv[])
{
   //code
}

C ++ 我知道我们可以重载的方法,但在 C 编译器如何处理这两个不同函数的签名?

In C++ I know we can overload a method, but in C how does the compiler handle these two different signatures of main function?

推荐答案

一些C语言的特点开始了作为刚好工作黑客。

Some of the features of the C language started out as hacks which just happened to work.

有关主,以及可变长度参数列表,多个签名是其中的功能之一。

Multiple signatures for main, as well as variable-length argument lists, is one of those features.

程序员发现,他们可以通过额外的参数的函数,并没有什么不好与他们给出的编译器发生。

Programmers noticed that they can pass extra arguments to a function, and nothing bad happens with their given compiler.

此情况下,如果调用约定是这样的:

This is the case if the calling conventions are such that:


  1. 调用函数清理参数。

  2. 最左边的参数更接近栈的顶部,或在堆栈帧的基础上,使杂散参数不无效寻址。

一组调用其遵守这些规则的约定是基于堆栈的参数传递,从而来电弹出的参数,并且他们都推从右到左:

One set of calling conventions which obeys these rules is stack-based parameter passing whereby the caller pops the arguments, and they are pushed right to left:

 ;; pseudo-assembly-language
 ;; main(argc, argv, envp); call

 push envp  ;; rightmost argument
 push argv  ;; 
 push argc  ;; leftmost argument ends up on top of stack

 call main

 pop        ;; caller cleans up   
 pop
 pop

在编译器,其中这种类型的调用约定的情况下,没有什么特别需要做支持两种,甚至更多种。 可以是无参数的函数,在这种情况下,无视被压入堆栈的项目。如果它的两个参数的函数,那么它找到 ARGC 的argv 作为两个最顶层的栈项目。如果它是一个特定于平台的三个参数的变异与环境指针(一种常见的扩展名),将工作太:它会发现第三个参数从堆栈的顶部第三个元素

In compilers where this type of calling convention is the case, nothing special need to be done to support the two kinds of main, or even additional kinds. main can be a function of no arguments, in which case it is oblivious to the items that were pushed onto the stack. If it's a function of two arguments, then it finds argc and argv as the two topmost stack items. If it's a platform-specific three-argument variant with an environment pointer (a common extension), that will work too: it will find that third argument as the third element from the top of the stack.

和这样的固定呼叫适用于所有的情况下,允许一个单一的,固定的启动模块链接到该程序。该模块可以用C写的,因为这种类似的函数:

And so a fixed call works for all cases, allowing a single, fixed start-up module to be linked to the program. That module could be written in C, as a function resembling this:

/* I'm adding envp to show that even a popular platform-specific variant
   can be handled. */
extern int main(int argc, char **argv, char **envp);

void __start(void)
{
  /* This is the real startup function for the executable.
     It performs a bunch of library initialization. */

  /* ... */

  /* And then: */
  exit(main(argc_from_somewhere, argv_from_somewhere, envp_from_somewhere));
}

在换句话说,这个启动模块只是调用三个参数的主力,总是如此。如果主不带任何参数,或仅 INT,CHAR ** ,它发生做工精细,以及如果不带任何参数,由于调用约定。

In other words, this start module just calls a three-argument main, always. If main takes no arguments, or only int, char **, it happens to work fine, as well as if it takes no arguments, due to the calling conventions.

如果你做这种事情在你的程序中,这将是不可移植的,并认为不确定的行为由ISO C:声明和一个方式调用一个函数,而在另一个定义它。但是编译器的启动招不必为手提式的;它不被用于移植的程序的规则的指导。

If you were to do this kind of thing in your program, it would be nonportable and considered undefined behavior by ISO C: declaring and calling a function in one manner, and defining it in another. But a compiler's startup trick does not have to be portable; it is not guided by the rules for portable programs.

但是假设调用约定是这样的,它无法以这种方式工作。在这种情况下,编译器治疗特别。当它注意到,它的编译的功能,它可以生成code这是与,比如说兼容,三个参数调用。

But suppose that the calling conventions are such that it cannot work this way. In that case, the compiler has to treat main specially. When it notices that it's compiling the main function, it can generate code which is compatible with, say, a three argument call.

这是说,你这样写:

int main(void)
{
   /* ... */
}

但是,当编译器看到它,它基本上是执行code改造,这样它编译功能看起来更像是这样的:

But when the compiler sees it, it essentially performs a code transformation so that the function which it compiles looks more like this:

int main(int __argc_ignore, char **__argv_ignore, char **__envp_ignore)
{
   /* ... */
}

除了名称 __ argc_ignore 不要随便存在。没有这样的名字被引入到你的范围,不会有关于未使用变的警告。
在code转型导致编译器发出code与知道它清理三个参数的正确连接。

except that the names __argc_ignore don't literally exist. No such names are introduced into your scope, and there won't be any warning about unused arguments. The code transformation causes the compiler to emit code with the correct linkage which knows that it has to clean up three arguments.

另一种实施策略是编译器或者连接器来定制生成 __启动函数(或任何它被称为),或至少从几个$ P选择一个$ p-编译的替代品。信息可以存储约,其中主要的支持形式正在使用的对象文件英寸链接器可以看一下这个信息,并选择其中包含主呼叫时启动模块的正确版本这与节目的定义不兼容。 C实现通常只有少数支持的主要形式所以这种方法是可行的。

Another implementation strategy is for the compiler or perhaps linker to custom-generate the __start function (or whatever it is called), or at least select one from several pre-compiled alternatives. Information could be stored in the object file about which of the supported forms of main is being used. The linker can look at this info, and select the correct version of the start-up module which contains a call to main which is compatible with the program's definition. C implementations usually have only a small number of supported forms of main so this approach is feasible.

对于C99语言编译器总是有治疗特殊,在一定程度上支持了黑客攻击,如果函数结束没有回归声明,该行为是因为如果返回0 被处决。这又可以由code转换处理。调用一个函数主要的编译器会正在编制。然后它检查体的端是否是潜在的可达。如果是这样,它插入一个返回0;

Compilers for the C99 language always have to treat main specially, to some extent, to support the hack that if the function terminates without a return statement, the behavior is as if return 0 were executed. This, again, can be treated by a code transformation. The compiler notices that a function called main is being compiled. Then it checks whether the end of the body is potentially reachable. If so, it inserts a return 0;

这篇关于如何在C main()方法的工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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