为什么在将main声明为`int main(void)`时传递命令行参数时没有错误?

Gee*_*kyJ 14 c program-entry-point command-line-arguments

情况1:

void hello(void) {
    //something
}

int main()
{
    hello(1); //error
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

案例2:

int main(void) {
    //something
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

执行:

./a.out something something //No error, Why?
Run Code Online (Sandbox Code Playgroud)

为什么没有错误?main将无法采取任何论点.那么为什么可以从命令行提供参数呢?

gna*_*729 14

因为C编译器和命令行解释器(或用于调用程序的任何东西)是不同的东西.

C语言允许以各种方式声明main().

命令行解释器将使程序可以使用任何参数.如果程序忽略它们,那就不是它的业务.

命令行解释器甚至不知道您使用C编译程序.在我的计算机上,程序可以用C,C++,Objective-C,Objective-C++,Swift,Fortran,Ada等编写.这些编译器中的每一个都可能会或可能不会从命令行接受命令.


Mik*_*CAT 9

不检查规范或编译结果,它不会导致错误,因为C运行时将获取参数并将它们传递给main(),但是这种类型main()将忽略传递的参数,并且如果调用者有责任清理内存(堆栈)用作参数,它将不会产生任何问题,就像获取一些参数而不在代码中使用它们一样.

此代码不会在C中发出错误:

void hello(); // in C, the compiler won't check arguments

int main() {
    hello(1); //no error
    return 0;
}

void hello(void) {
    //something 
}
Run Code Online (Sandbox Code Playgroud)

  • @Jongware传递给`main`的参数通过*调用*`main`函数从堆栈中清除,这是一个由C库提供的填充程序,并且该函数不知道或不关心如何声明`main` .这对于'main`来说并不特别; 这是所有函数的正常C调用约定.(像`__stdcall`这样的编译器扩展可以改变约定.如果将它们应用于`main` - 或者应用于C库调用的任何其他函数,就会发生糟糕的事情.) (3认同)
  • @Jongware啊,你可能会问的另一件事*.`argv`首先来自哪里?作为[`execve`](http://linux.die.net/man/2/execve)操作的一部分,内核将它与程序一起加载到内存中,并构造一个初始调用框架,告诉C库的启动代码在哪里找到它.它通常是*在堆栈的最顶层,但它不一定是,并且它永远不会被释放. (2认同)
  • @zwol:这一定是OP正在寻找的答案.运行时启动*always*告诉C代码在哪里找到参数 - 是否存在参数.它并不关心C代码是否真的很难检查. (2认同)

tap*_*and 5

因为./a.out something something不是直接调用你的主要功能.主要功能由c运行时库调用.命令行参数由loader/c运行时放置在堆栈中的某个区域(最开始).如果您想要访问这些参数,则由您决定.

另外,正如其中一条评论所指出的那样,至少有一个命令行参数总是被传递(程序的名称./a.out要精确) - 所以你必须在这种情况下想知道错误.