【问题标题】:What main(++i) will return in C什么 main(++i) 将在 C 中返回
【发布时间】:2014-10-24 03:02:21
【问题描述】:

我有一个这样的程序。

‪#include<stdio.h>
#include<stdlib.h>

int main(int i) {                /* i will start from value 1 */
if(i<10)                        
printf("\n%d",main(++i));        /* printing the values until i becomes 9 */    
}

output : 
5
2
2
2

谁能解释一下输出是怎么来的?每次迭代返回什么 main(++i)。 如果我删除 printf 函数中的 \n ,它也会产生输出 5111。 提前致谢。

【问题讨论】:

  • @Jayesh 调用 main 在 C 中是合法的。但 main 不带一个 int 参数。
  • int main(i) 不是有效的函数声明。
  • i will start from value 1 i think 不会。 main() 应该是 int main(int argc, char **argv) 并且系统会这样调用它,你不能随心所欲。有些编译器甚至不接受这个。
  • 另外,您的 printf() 正在打印 main() 的返回值,但是,您的函数 main() 不返回任何内容。这些数字是内存垃圾,未定义的行为。
  • 为什么初学者对非常糟糕代码的工作原理如此感兴趣,而不是学习如何编程?

标签: c return main


【解决方案1】:

这个程序到处都有undefined behavior (UB),如果你的程序中有一个未定义的实例行为,你不能安全地假设你的程序的任何输出或行为 - 它可以合法地发生任何事情(尽管在现实世界中,效果通常在代码中靠近 UB 的位置进行局部化。 列出的旧 C90 标准是 100 多个(如果我没记错的话)UB 情况,并且顶部有未知数量的 UB,这是针对情况的行为,标准没有描述。每个 C 和 C++ 标准都存在一组情况,即 UB。

在你的情况下(没有咨询标准)UB的实例至少是:

  • 不返回用返回值声明的函数的值。 (例外:第一次调用 main - 感谢 Jim 的 cmets)
  • 定义(和调用)main,而不是使用标准的预定义形式,或由编译器指定(作为实现定义的行为)。

由于您的程序中至少有一个 UB 实例,因此对结果的推测有点……推测性,并且必须对您的编译器、操作系统、硬件甚至并行运行的软件做出假设,即通常没有记录或可以知道。

【讨论】:

  • 在 C 程序中调用 main不是未定义的行为(C++ 不允许但 C 不允许)。该标准甚至在描述程序终止时提到“对主函数的初始调用”(强调添加)。 “不返回使用返回值声明的函数的值”——这是main不正确——C 标准对此做了一个特殊的例外。
  • @Jim 谢谢,这很有趣。在 C 标准的每个化身中都有这个例外吗?它适用于每次通话还是仅适用于第一次通话?
  • 在OP的代码中实际上UB的具体来源有3个:main的错误定义,i&lt;10i的值,main(...)的返回值。
  • 它在每个化身中,只适用于初始调用:“如果主函数的返回类型是与int兼容的类型,则从初始调用返回到主函数相当于调用以 main 函数返回的值作为参数的 exit 函数;到达终止 main 函数的 } 返回值 0。” -- 至少,我认为返回值 0 仅适用于初始调用……在我看来,这种语言实际上是模棱两可的。 OP 的实现肯定不像main 返回 0。
  • @JimBalter 为什么比较中“i”的值未定义(不仅仅是主调用中的错误)?
【解决方案2】:

我认为,主要方法是在主要方法中调用自己。 为了增加一个变量的值,i++ 在它增加之前打印 i 的值,而 ++i 它在打印 i 的值之前先增加 i 的值。

你可以用这个..

int x=0;
main()
{
   do
   {
   printf(x++);
   }while (i<10);

} 

【讨论】:

  • 我认为,main 方法是在 main 方法中调用自己。 -- 这很明显。 为了增加一个变量的值,i++ 在它增加之前打印 i 的值,而 ++i 它在打印 i 的值之前先增加 i 的值。 -- 这没有关系关于问题。并且i 的值在给定代码中未打印,无论是预先递增还是后递增。 你可以用这个..——这无关紧要。这里有一个具体的问题,你没有做任何回答。
【解决方案3】:

首先,main() 的声明应该是int main(int argc, char **argv)。你不能修改它。即使你的代码编译了,系统也会以它应该被调用的方式调用main(),第一个参数是你程序的参数数量(如果没有给出参数,则为1)。不能保证它永远是 1。如果你用额外的参数运行你的程序,这个数字会增加。

其次,您的printf() 正在尝试打印main(++i) 的返回值,但是,您的main() 根本不返回任何内容。如果您希望在这里看到任何连贯性,则必须为您的函数提供一个返回值。

最后,你不应该调用你自己程序的入口点,更不用说使用递归了。为这些东西创建一个单独的函数。

【讨论】:

  • "首先,main() 的声明应该是 int main(int argc, char **argv)。" ——不一定; C 标准明确允许int main(void),以及“其他一些实现定义的方式”。 “第一个参数是程序的参数数量”——如果 main 定义正确,这是正确的,但是当 OP 以这种方式定义时,不能保证 int i 将映射到传递的第一个参数系统。 “你不应该调用你自己程序的入口点”——C 标准(与 C++ 相比)中没有任何内容说你不能。
  • @JimBalter 实际上,使用int main(void) 你只是说你不关心这些论点。无论如何,系统仍然会发送它们,只是没有任何与堆栈地址 EBP+8 (argc) 和 EBP+12 (argv)(假设为 32 位)关联的变量名来获取它们。
  • 您可以尝试实际阅读我写的内容:“当以 OP 的方式定义时”——这不是int main(void)。 “你只是说你不关心这些论点”——呃。 “无论如何,系统仍会发送它们” - 呃。 “你不会有任何变量名”——OP 有一个变量名...i。就像我说的,“不能保证 int i 会映射到系统传递的第一个参数”。您的评论没有解决这个问题(或我写的任何其他内容)。
  • 实际上调用约定保证了这一点。
  • 引文?或者换一种说法:你不知道你在说什么。当您甚至不知道 OP 使用的是什么机器时,您假设使用 EBP+8 等特定的调用约定已经够糟糕了。
【解决方案4】:

我很惊讶竟然可以编译。

当操作系统实际运行程序并调用 main() 时,会将两个 32(或 64)位值传递给它。您可以通过声明 main(void) 来忽略它们,或者通过声明 main(int argc, char** args) 来使用它们。

正如上面的原型所暗示的,传递的第一个值是传递给进程的命令行参数数量的计数,第二个是指向这些参数列表存储在内存中的位置的指针,可能在程序的本地堆栈上。

argc 的值始终至少为 1,因为 args 中的第一项字符串始终是程序本身的名称,由操作系统生成。

关于您的意外输出,我想说一些东西没有被拉出或压入堆栈,因此变量被混淆了。这可能是由于 main() 的参数列表不完整,或者您已声明 main 返回一个 int,但没有返回任何内容。

【讨论】:

  • “我很惊讶竟然能编译。” ——我不明白为什么人们对此感到惊讶。该标准明确指出该实现不提供main 的原型,因此任何定义都可能编译,除非编译器竭尽全力阻止它——而标准并不要求这样做。当然,有些编译器会给出警告。
【解决方案5】:

您没有初始化 i,因此默认值将取自它存储在 RAM 中的地址。

如果您在重新启动计算机后多次运行该代码,此代码将产生垃圾输出。

输出也将取决于编译器。

【讨论】:

  • i 的值仅与i&lt;10 测试相关...main 不返回它,因此它与打印的内容无关。 “如果您在重新启动计算机后多次运行该代码,此代码将产生垃圾输出。” -- 嗯,不,因为在所有现代操作系统上运行程序之前都会清除内存......结果是相当确定的,尽管未指定。
【解决方案6】:

以下是 C 草案标准 (N1570) 关于main 的内容:

5.1.2.2.1 程序启动

1 程序启动时调用的函数名为main。实现声明没有 这个函数的原型。它应定义为返回类型int,并且没有 参数:

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

或带有两个参数(此处称为argcargv,尽管可以是任何名称 使用,因为它们在声明它们的函数中是本地的):

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

或等效或以其他实现定义的方式。

很明显,你程序中的main函数不是上述两种形式。除非您的平台支持您使用的表单,否则您的程序会表现出未定义的行为。

【讨论】:

    猜你喜欢
    • 2010-09-17
    • 1970-01-01
    • 2014-02-25
    • 2015-12-13
    • 2011-06-18
    • 2016-11-27
    相关资源
    最近更新 更多