【问题标题】:what's the meaning of exit code of program with empty void main()?带有空 void main() 的程序的退出代码是什么意思?
【发布时间】:2020-07-16 15:53:12
【问题描述】:

我做了一个简单的 C 程序,下面给出了一个空的 main 并用 gcc 编译它

void main(){
}

在执行时,它返回退出代码为25, 如果我添加一个 printf 语句,在包含 stdio.h 之后,它会返回退出代码5

这里的255 是什么意思,为什么main() 之前或之后执行的任何代码都会返回它? 如果我使用 int main() 并且不放置 return 语句,则退出代码为零。

【问题讨论】:

  • 问题标题说你有void main(),但问题正文说你正在执行一个带有int main()的程序。请澄清。
  • 如果您在 C99 或更高版本中编译,退出状态必须为零。在 C90 模式下,它是不确定的。
  • 不同长度的 printf(printf("five\n");printf("2\n");)可能返回码不同。
  • @JohnBollinger 编辑问题以澄清
  • @pmg 返回值是打印字符串的长度

标签: c linux shell gcc exit-code


【解决方案1】:

这里的25和5是什么意思

C 语言规范没有定义 main() 被声明为返回 void 的程序的行为。尽管如此,接受此类代码的实现可能会或可能不会为其定义行为。那么,在一般意义上,no 退出状态对于具有void main() 的程序具有任何意义或意义。

显然,GCC 确实接受该代码,但我在 GCC's documented C extensions 中找不到其行为的定义,因此在这种特殊情况下,您观察到的退出状态都没有任何意义。

以及为什么它被退回 在 main() 之前或之后执行的代码是什么?

没有特别的原因。行为未定义。

退出代码是 如果我使用 int main() 并且不添加 return 语句,则为零。

这种情况是很好定义的。 C 指定如果执行到达对main() 的初始调用结束(假定使用两个C 标准签名之一声明,两者都返回int),则行为就像调用exit(0)。这是一个特例。如果执行到达非void 函数的右大括号,并且其调用者对返回值进行任何操作,则行为未定义。

【讨论】:

  • 从纯实现的角度来看,OP得到这些返回值的原因是GCC在从void函数返回时没有将任何内容写入返回值寄存器(因为为什么会这样?) ,但_start 代码在main 返回后从该寄存器读取,因为它期望main 返回int。所以结果将是main 返回时该寄存器中发生的任何事情。
【解决方案2】:

(补充约翰·博林格的回答)

* 空主

旧的 ISO C 标准 (ISO/IEC 9899:1999) 声明:

[main] 应该被定义

  • 返回类型为int
    • 没有参数 […] 或
    • 带有两个参数 […] 或等效参数; 或
    • 以其他一些实现定义的方式。

§ 5.1.2.2.1 ¶ 1 的 C 标准

如果返回类型与int不兼容,则返回宿主环境的终止状态未指定。

§ 5.1.2.2.3 ¶ 1

这表明允许不返回 int 的表单是故意的。

许多编译器手册(例如 Watcom C/C++、IBM VisualAge C/C++、Microsoft Visual C/C++)指出main 的返回类型可能为void,因此带有void main() 的程序是符合标准的程序。

很长一段时间以来,许多代码的返回类型都是voidgcc(可能)认为与遗留代码兼容很重要,并允许 void main() 但在这种情况下:

  • 它会发出警告 (warning: return type of ‘main’ is not ‘int’);
  • 程序的返回值未定义。

参考资料:

* int main

int main() {}

这在 C89/90 中未定义,但在以下版本中定义良好(返回 0)。

* 实际值

在 x86 上,EAX 寄存器通常用于返回值。所以

int main() {}

被编译成类似:

main:
        push    rbp
        mov     rbp, rsp
        mov     eax, 0
        pop     rbp
        ret

对于

void main() {}

最简单的操作是删除mov eax, 0

main:
        push    rbp
        mov     rbp, rsp
        nop
        pop     rbp
        ret

如果添加printf 语句:

#include <stdio.h>

void main()
{
  printf("1234");
}

你得到:

.LC0:
        .string "1234"
main:
        push    rbp
        mov     rbp, rsp
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        pop     rbp
        ret

printf 调用改变了EAX 寄存器(返回写入流的字符数,EAX 用于返回值)。

【讨论】:

  • @EricPostpischil 谢谢你,你是对的。我已经确定了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-30
  • 2023-03-21
  • 1970-01-01
  • 2012-02-29
相关资源
最近更新 更多