int main() 和 int main(void) 之间的区别?
Posted
技术标签:
【中文标题】int main() 和 int main(void) 之间的区别?【英文标题】:Difference between int main() and int main(void)? 【发布时间】:2012-08-26 20:26:20 【问题描述】:以下是什么意思:
int main(void) ...
VS
int main() ...
?
我认为int main() ...
意味着 main 没有收到任何参数(来自命令行),但是:
int main(int argc, char *argv[])
会。
但是,int main(void) ...
是什么意思?还有,void 代表什么?
我看过here,但不知何故这是一个不同的问题。
【问题讨论】:
C99 和 C11 不再提及int main()
。只需使用int main(void)
。见标准5.1.2.2.1“程序启动”:open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
相关:Is int main() (without “void”) valid and portable in ISO C?
【参考方案1】:
在C++中,两者没有区别,int main()
是main
的合法签名和返回类型。
【讨论】:
【参考方案2】:在 C 中,在 prototype 中(虽然不是在 C++ 中)一个空参数列表意味着函数可以接受 any 参数(在函数的定义中,它表示没有参数)。在 C++ 中,空参数列表意味着没有参数。在 C 中,要获得无参数,您必须使用 void
。请参阅this 问题以获得更好的解释。
【讨论】:
仅当声明符不是函数定义的一部分时才适用。 @eq-:对不起,但这意味着它只适用于与实现分开的情况?所以它适用于int foo(void); int foo(void)
,但不适用于int foo(void)
?
在 C 中,int foo();
不指定函数参数的任何内容,而 int foo()
指定 foo
不带任何参数。
C 语言错误。标准甚至在其示例中包含 int main() ...
。
在定义中,空括号 as a definition 告诉编译器它不接受任何参数,而是作为 declaration (在that) 表示它需要 unspecified 数量的参数),所以它同时是两者。【参考方案3】:
在 C++ 中,没有区别。
在 C 中,差异是值得怀疑的。有些人喜欢争辩说,后一个版本(没有void
的版本)在技术上只是一种常见的实现扩展,并且由于标准中的措辞而不能保证按标准工作。但是,该标准明确指出,在函数定义中,一组空参数具有明确定义的行为:该函数不接受任何参数。因此,这样的 main 定义与标准中的以下描述相匹配:
It [main] 应定义为返回类型为 int 且不带参数。
然而,两者之间有一个明显的区别:即没有void
的版本无法为函数提供正确的原型:
// this is OK.
int main()
if (0) main(42);
// this requires a diagnostic to be shown during compiling
int main(void)
if (0) main(42);
哦,顺便说一句:void
在所有函数声明符中都具有以下含义:
(6.7.6.3p10) 类型为 void 的未命名参数作为列表中唯一项的特殊情况指定该函数没有参数。
【讨论】:
在您的第一个示例中,main(42);
是什么意思(您在哪里写了// this is okay
)?
这是一个函数调用(main
的单个 int 参数为 42
)。
是的,但它有什么作用?这是我第一次在 main() 中看到 main() 的调用。
+1 用于清除该神话。我只是不同意它不是原型的部分。术语“原型”不是通过语法而是通过语义定义的,它是函数的声明,它也声明了其参数的类型。 int main() ...
非常适合,在那里。并非所有编译器都同意这一点,但这是不同的一点:)
@JensGustedt 毫无疑问,但结论不是你所期望的。 int main()
不提供原型。这是一个常见的讨论点,但委员会在DR #317 中提供了明确的答案:“语法规定空括号代表空标识符列表而不是空参数类型列表。”【参考方案4】:
在 C++ 中,函数 foo(void)
和 foo()
是一回事。但是,在 C 中则不同:foo(void)
是一个没有参数的函数,而 foo()
是一个没有指定参数的函数。
【讨论】:
您错过了重点(对于 C)。在int foo()
的定义中声明了一个没有参数的函数。
@JensGustedt 在 C 中,在定义中,int foo()
实际上定义 一个没有参数的函数,但它声明 一个接受未指定参数的函数参数数量。【参考方案5】:
在C++中,没有区别,都是一样的。
这两个定义也可以在 C 中使用,但是第二个带有 void 的定义在技术上被认为更好,因为它清楚地指定 main 只能在没有任何参数的情况下调用。 在 C 语言中,如果函数签名没有指定任何参数,则意味着可以使用任意数量的参数或不使用任何参数来调用该函数。例如,尝试编译并运行以下两个 C 程序(请记住将文件另存为 .c)。
【讨论】:
【参考方案6】:首先,托管系统和独立系统所允许的内容有所不同,如shown here。
对于托管系统,适用 5.1.2.2.1 程序启动:
程序启动时调用的函数名为main。实现声明没有 这个函数的原型。它应定义为返回类型为 int 并且没有 参数:
int main(void)
...(后面有更多关于 argv/argc 等样式的文字)。
有趣的部分是“没有参数”。 int main()
和 int main (void)
目前是等价的,因为它们都是函数声明符并且没有参数。以下适用(6.7.6.3):
10 void 类型的未命名参数作为列表中唯一项的特殊情况指定该函数没有参数。
/--/
14 标识符列表仅声明函数参数的标识符。 一个空的 作为该函数定义一部分的函数声明器中的 list 指定 函数没有参数。 函数声明器中不属于 该函数的定义指定没有关于函数的数量或类型的信息 提供参数。145)
强调我的,粗体字适用于int main()
。文末还有注释 145),上面写着“参见‘‘未来的语言方向’(6.11.6)”:
6.11.6 函数声明符
使用带空括号的函数声明符(不是原型格式的参数类型声明符)已过时。
这就是区别。作为一个函数声明器,int main()
是不好的风格,因为上述原因,因为它不能保证在下一版本的 C 标准中工作。它在 C11 中被标记为过时的功能。
因此,您应该始终在托管系统上使用int main (void)
,而不是int main()
,即使目前这两种形式是等效的。
在 C++ 中,这两种形式是完全等价的,但出于主观、美观的原因,int main()
是首选风格(Bjarne Stroustrup 这么说……这可能是解释你为什么以特定方式做某事的一个非常糟糕的理由)。
【讨论】:
“int main()
是出于主观、美观原因的首选风格”——也许是主观的,好吧,但 IMO 它仍然是正确的。 ()
显然是一个空元组。 (void)
看起来像是 void
类型的单个参数,然后你会期望能够编写像 main(f())
这样的东西,如果 f
是一个“返回 void”的函数。区分空集(/lists/arrays/tuples)和其成员恰好是空的单元素集是一个好主意。 (除此之外,如果客观上写void
与否无关紧要,那么请遵循奥卡姆的样板剃刀......【参考方案7】:
我知道线程很旧,但几年前这个问题困扰了我一段时间,所以我想投入我的半分钱(如果是这样的话)。
我总是将 C 函数视为具有固定数量的参数,而不管上下文如何,除非它们使用 va_args。也就是说,我相信 main 总是有原型:
int main(int argc, char **argv).
即使没有传递参数,该函数在堆栈上也有这些参数,因为主函数没有函数重载。
C 确实有能力通过假装参数不存在来进行原始重载。在这种情况下,参数仍然被传递并且在堆栈上,但你永远不会访问它,所以它只是减少了源代码的大小。
说int main()只是表示我知道函数可能有参数,但我没有使用,所以我写了int main()。
说 int main(void) 表示 main 肯定没有参数,并暗示有两个不同的函数原型:
int main(void);
int main(int argc, char **argv);
由于 C 没有函数重载,这对我来说有点误导,我不信任其中包含 main(void) 的代码。如果 main 不带任何参数,我不会这样做,在这种情况下 main(void) 完全可以。
注意:在某些实现中,main 中的参数比 argc 和 argv 多,例如 env,但这并不困扰我,因为我知道我并没有明确说这是仅有的两个参数,但那些是最小的参数,可以有更多,但不能更少。这与直截了当地说 int main(void) 大喊大叫,因为这个函数没有参数,这是不正确的,因为它有,它们只是被省略了。
这是我的基本代码:
/* sample.c - build into sample. */
#include <stdio.h>
int main(void)
int _argc = *((int *)2686800);
char ***_pargv = (char ***)2686804;
int i;
for (i = 1; i < _argc; ++i)
printf("%s ", (*_pargv)[i]);
return 0;
./sample 我显然有论据
该函数显然有传递给它的参数,尽管通过在函数原型中键入 void 明确表示它没有。
如上所述:
(6.7.6.3p10) void 类型的未命名参数的特殊情况作为 列表中只有一项指定该函数没有参数。
因此说函数有 void 作为参数但实际上在堆栈上有参数是矛盾的。
我的观点是参数仍然存在,因此明确断言 main 没有参数是不诚实的。诚实的方法是说 int main(),它不声明它有多少参数,只声明你关心多少参数。
注意 2:_argc、_pargv 依赖于系统,要找到您的值,您必须通过运行此程序找到它们:
/* findargs.c */
#include <stdio.h>
int main(int argc, char **argv)
printf("address of argc is %u.\n", &argc);
printf("address of argv is %u.\n", &argv);
return 0;
对于您的特定系统,这些值应该保持正确。
【讨论】:
【参考方案8】:在 C++ 中,int main() 和 int main(void) 没有区别。 但在 C 中,它们有点不同。 int main() 表示主函数可以带任意数量的参数或不带任何参数调用。另一方面,int main(void)表示将不带任何参数调用main函数
#include <stdio.h>
int main()
static int i = 5;
if (--i)
printf("%d ", i);
main(10);
输出:4 3 2 1
#include <stdio.h>
int main(void)
static int i = 5;
if (--i)
printf("%d ", i);
main(10);
它会显示错误。因为,
int main(void)
中的参数是 void 但在程序中我们采用了main(10)
(它定义了一些值,而不是 void)
【讨论】:
【参考方案9】:从技术上讲,如果您的主机部分符合 POSIX,那么您就有
int main(); // this legacy is always used by the run time library
int main(int argc); // illegal by compiler
int main(int argc, char** argv); // required by C standards
int main(int argc, char** argv, char** envp); // required by POSIX standard
如果你有 Mac,也有这个
int main(int argc, char** argv, char** envp, char** apple); // required by Macintosh standard
您的主机将发送所有参数,因此主机将始终发送 argc、argv 和 envp(如果您使用的是 Apple 产品,还有苹果),但程序员可以将其main
声明为无效。隐式函数指针类型转换在技术上是一种未定义的行为。
为了防止类型转换未定义行为,int main()
是一种中性形式,这意味着它可以使用规范类型提升(int 或更大,以及 double 或更大)采用任何固定数量的参数,int main(int argc, ...)
意味着它可以采用任何可变数量的参数也具有规范类型提升。换句话说,return_type function_name()
形式是未定义行为的例外。
【讨论】:
以上是关于int main() 和 int main(void) 之间的区别?的主要内容,如果未能解决你的问题,请参考以下文章
int main() 和 int main(void) 之间的区别?
int main(int argc, char* argv[]) 和 int main(int argc, char** argv) [关闭]
int main(int argc,char* argv[])详解