63

以下是什么意思:

int main(void) {...} 

VS

int main() {...}

?

我认为这int main() {...}意味着 main 没有收到任何参数(来自命令行),但是:

int main(int argc, char *argv[])

做。

但是,是什么int main(void) {...} 意思?还有,代表什么?

我看过这里,但不知何故这是一个不同的问题。

4

9 回答 9

54

在 C++ 中,没有区别。


在 C 中,差异是值得怀疑的。有些人喜欢争辩说,后一个版本(没有 的版本void)在技术上只是一个常见的实现扩展,并且由于标准中的措辞而不能保证按照标准工作。但是,该标准明确指出,在函数定义中,一组空参数具有明确定义的行为:该函数不接受任何参数。因此,这样的 main 定义与标准中的以下描述相匹配:

它 [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 的未命名参数作为列表中唯一项的特殊情况指定该函数没有参数。

于 2012-09-01T05:38:05.497 回答
6

首先,托管系统和独立系统所允许的内容有所不同,如此处所示

对于托管系统,适用 5.1.2.2.1 程序启动:

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

int main(void)

...(更多关于 argv/argc 等样式的文字如下)。

有趣的部分是“没有参数”。int main()并且int main (void)目前是等价的,因为它们都是函数声明符并且没有参数。以下适用(6.7.6.3):

10 void 类型的未命名参数作为列表中唯一的项目的特殊情况指定该函数没有参数。

/--/

14 标识符列表仅声明函数参数的标识符。作为该函数定义的一部分的函数声明器中的空列表指定该函数没有参数。不属于该函数定义的函数声明器中的空列表指定不提供有关参数数量或类型的信息。145)

强调我的,粗体文本适用于int main(). 文末还有注释 145),上面写着“参见‘未来语言方向’(6.11.6)”:

6.11.6 函数声明器

使用带空括号的函数声明符(不是原型格式参数类型声明符)是一个过时的特性。

这就是区别。由于上述原因,作为函数声明int main()器是不好的风格,因为它不能保证在下一版本的 C 标准中工作。它在 C11 中被标记为过时的功能。

因此,您应该始终int main (void)在托管系统上使用,并且永远不要使用int main(),即使这两种形式目前是等效的。


在 C++ 中,这两种形式是完全等价的,但int main()出于主观、美观的原因,存在首选风格(Bjarne Stroustrup 这么说……这可能是解释为什么以特定方式做某事的一个非常糟糕的理由)。

于 2015-07-10T08:48:36.503 回答
5

在 C 中,在原型中(虽然不是在 C++ 中),空参数列表意味着函数可以接受任何参数(在函数的定义中,它意味着没有参数)。在 C++ 中,空参数列表意味着没有参数。在 C 中,要获得没有参数,您必须使用void. 请参阅问题以获得更好的解释。

于 2012-09-01T05:37:56.643 回答
4

在 C++ 中具有一个函数foo(void)foo()是一回事。但是,在 C 语言中则不同:foo(void)是没有参数的函数,而foo()是具有未指定参数的函数。

于 2012-09-01T05:38:14.097 回答
3

在 C++ 中,没有区别,两者都是一样的。

这两个定义在 C 中也有效,但是第二个带有 void 的定义在技术上被认为更好,因为它清楚地指定 main 只能在没有任何参数的情况下调用。在 C 语言中,如果函数签名没有指定任何参数,则意味着可以使用任意数量的参数或不使用任何参数来调用该函数。例如,尝试编译并运行以下两个 C 程序(请记住将文件另存为 .c)。

于 2015-05-23T03:05:05.437 回答
1

在 C++ 中,两者没有区别,int main()是合法的签名和返回类型main

于 2012-09-01T05:31:50.097 回答
0

我知道线程很旧,但是几年前这个问题困扰了我一段时间,所以我想投入我的半分钱(如果那样的话)。

无论上下文如何,我总是将 C 函数视为具有固定数量的参数,除非它们使用 va_args。也就是说,我相信 main 总是有原型:

int main(int argc, char **argv).

即使没有传递参数,该函数在堆栈上也有这些参数,因为主函数没有函数重载。

C 确实有能力通过假装参数不存在来进行原始重载。在这种情况下,参数仍然被传递并且在堆栈上,但你永远不会访问它,所以它只是减少了源代码的大小。

说int main()只是表示我知道函数可能有参数,但是我没有使用,所以我写了int main()。

说 int main(void) 表示 main CERTAINLY 没有参数,并暗示有两个不同的函数原型:

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 明确表示它没有。

如 eq- 上面所说:

(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;
}

对于您的特定系统,这些值应该保持正确。

于 2016-03-24T02:47:17.973 回答
0

在 C++ 中, int main()int main(void)之间没有区别。
但在 C 中,它们有点不同。
int main()表示主函数可以带任意数量的参数或不带任何参数调用。另一方面,int main(void)表示将在没有任何参数的情况下调用主函数

#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); 
    } 
} 

它会显示错误。因为,inint main(void)参数是 void 但在我们采用的程序中main(10)(它定义了一些值,而不是 void)

于 2020-11-21T19:44:23.393 回答
0

从技术上讲,如果您的主机部分符合 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()是未定义行为的例外。

于 2021-11-30T05:24:31.313 回答