gpt4 book ai didi

c++ - C 中的 main() 方法是如何工作的?

转载 作者:IT老高 更新时间:2023-10-28 11:56:41 26 4
gpt4 key购买 nike

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

int main()
{
//Code
}

或者为了处理命令行参数,我们把它写成-
int main(int argc, char * argv[])
{
//code
}

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

最佳答案

C 语言的一些特性最初只是碰巧起作用的 hack。

main 的多个签名以及可变长度的参数列表是这些功能之一。

程序员注意到他们可以将额外的参数传递给函数,并且他们给定的编译器不会发生任何不好的事情。

如果调用约定如下:

  • 调用函数清除参数。
  • 最左边的参数更靠近堆栈顶部,或堆栈帧的底部,因此虚假参数不会使寻址无效。

  • 一组遵守这些规则的调用约定是基于堆栈的参数传递,调用者由此弹出参数,并将它们从右向左推送:
     ;; 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

    在这种类型的调用约定的编译器中,不需要做任何特殊的事情来支持这两种 main ,甚至其他种类。 main可以是一个没有参数的函数,在这种情况下,它不会注意到被压入堆栈的项目。如果它是一个有两个参数的函数,那么它会找到 argcargv作为最顶层的两个堆栈项。如果它是具有环境指针(通用扩展)的特定于平台的三参数变体,那也将起作用:它将找到第三个参数作为堆栈顶部的第三个元素。

    因此,固定调用适用于所有情况,允许将单个固定启动模块链接到程序。该模块可以用 C 编写,作为一个类似于以下的函数:
    /* 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));
    }

    换句话说,这个 start 模块总是调用一个三参数的 main。如果 main 没有参数,或者只有 int, char ** ,由于调用约定,它恰好可以正常工作,并且如果它不需要参数。

    如果您要在您的程序中执行此类操作,它将是不可移植的,并被 ISO C 视为未定义行为:以一种方式声明和调用函数,并以另一种方式定义它。但是编译器的启动技巧不必是可移植的;它不受可移植程序规则的指导。

    但是假设调用约定不能以这种方式工作。在这种情况下,编译器必须处理 main特别。当它注意到它正在编译 main 时函数,它可以生成与三个参数调用兼容的代码。

    也就是说,你这样写:
    int main(void)
    {
    /* ... */
    }

    但是当编译器看到它时,它本质上会执行代码转换,以便它编译的函数看起来更像这样:
    int main(int __argc_ignore, char **__argv_ignore, char **__envp_ignore)
    {
    /* ... */
    }

    除了名称 __argc_ignore不存在。不会在您的作用域中引入此类名称,并且不会对未使用的参数发出任何警告。
    代码转换使编译器发出具有正确链接的代码,该链接知道它必须清除三个参数。

    另一种实现策略是编译器或链接器自定义生成 __start函数(或任何名称),或至少从几个预编译的替代方案中选择一个。关于 main 支持哪种形式的信息可以存储在目标文件中。正在使用。链接器可以查看此信息,并选择包含对 main 的调用的启动模块的正确版本。这与程序的定义兼容。 C 实现通常只有少数受支持的形式 main所以这个方法是可行的。

    C99 语言的编译器总是要处理 main特别地,在某种程度上,支持黑客,如果函数在没有 return 的情况下终止声明,行为就像 return 0被处决。这同样可以通过代码转换来处理。编译器注意到一个名为 main 的函数。正在编译。然后它检查主体的末端是否可能可达。如果是这样,它会插入一个 return 0;

    关于c++ - C 中的 main() 方法是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19419569/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com