注册 登录
编程论坛 C++教室

这两种语句,C++什么标准?

yuma 发布于 2020-06-11 07:18, 4097 次点击
程序代码:
void main()
{
......
return;
}




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


这两种C++标准相同吗?
29 回复
#2
rjsp2020-06-11 08:37
第一段代码,从古至今,乃至于未来,在C/C++中都是错误的。

main 的返回值用于表明执行是否成功,这是一个约定的规定,如果用void,那调用者就会收到一个不确定的垃圾值,但调用者不知道这个值没意义呀,会根据这个值行事。
假如有个函数foo,大家规定好执行成功返回true,执行失败返回false。那么调用者就可以这么写:
if( foo(……) )
    执行下一步
else
    显示错误,中断流程。
但某个实现foo的傻逼没按规定返回指定值,那么上面的代码就乱套了。

假如要允许 void main 的话,那必然就得增加一个新的接口,告诉调用者main没有返回有意义的值。这不是简单的“脱裤子放屁”呀,这是“蛆虫为了吃口新鲜的屎,特意养了一个大活人”呀!
#3
ditg2020-06-26 21:01
完全错误倒也谈不上,起码有一点linux内核主函数直到今天依然在用void start_kernel(void),早期一直用main后来改了个名成现在的start_kernel,如果内核都在使用,为啥应用程序就不能使用了?

丹尼斯里奇(C的发明者)的书里连void都懒得写,直接就是main,我认为他知道应用程序其实就是一个子进程,如果要观察返回值,内核执行的加载执行程序exec函数每一步的返回值更重要或更有意义。

至于现在有的编译器不支持void,估计也就是后来这样明确写返回0的神级人物多了,约定成俗而已(个人观点)

[此贴子已经被作者于2020-6-26 21:09编辑过]

#4
rjsp2020-06-26 21:18
丹尼斯里奇(C的发明者)的书里连void都懒得写,直接就是main

因为K&D时代,C99之前,main函数省略返回类型,默认就是int。
那时候函数声明 foo(……)
就完全等同于函数声明 int foo(……)
#5
ditg2020-06-26 21:41
是滴,默认int,累加器里置0,现在有什么不一样吗?

比如,印象里您经常写int的时候省略返回值语句;换句话说,如果能够编译成功,相当于编译器一定遵从某个标准(具体我不知道)也会照常添加相应的置0语句,不管写还是不写return 0;

另外,就算最后返回的不是0值我觉得也没啥,也不代表程序就错了,不返回0值shell也不做任何处理,因为“程序执行完了”

[此贴子已经被作者于2020-6-26 21:53编辑过]

#6
rjsp2020-06-27 10:42
是滴,默认int,累加器里置0,现在有什么不一样吗?

之前没有“累加器里置0”这一规定,所以void main给调用者的就是一个不确定的数。

印象里您经常写int的时候省略返回值语句;

因为c99规定main的退出分支若无return语句则默认return 0。
而void main至始至终都是不合法的,标准从来规定要为一个不合法的函数去做什么。

另外,就算最后返回的不是0值我觉得也没啥,也不代表程序就错了,不返回0值shell也不做任何处理,因为“程序执行完了”

不代表程序错了,但你不知道它是不是错了。
比如你把数据保存到磁盘,没执行成功就要排除错误继续尝试保存,而不是不管不顾走人了。
比如你下载文件再处理,“下载文件”是个单独的程序,你执行了“下载文件”但不知道有没有成功,那你继续执行“处理”吗?
#7
rjsp2020-06-27 10:54
说个题外话,
在BIOS中,以前的legacy代码都是顶层执行者,没有调用者,很多人写 void main 或者 int main但无return。
efi提出时,为了复用旧程序,我就被安排检测各个编译器是否在不规范写法的情况下能return 0。
当时收集了IBM、Intel、amd、Phoenix、ami、ms等等所有联盟成员的所有编译器进行测试,测试结果是都不行。
#8
rjsp2020-06-27 11:48
一切 void main 能编译通过的编译器,不是因为编译器允许 void main,而是因为编译器没有堵上 void main 这个漏洞。
因此编译器也就不对针对 void main 进行防范(例如自动return 0;)

比如以前的绿皮火车,乘客可以跳窗自杀,并不是铁路管理局允许乘客跳窗自杀,而是铁路管理局没有堵上跳窗自杀这个漏洞。
既然懒得去堵上跳窗自杀这个漏洞,自动就不会在铁路两旁铺上软垫让跳窗者摔不死。

现在的高铁,直接就将窗户封死,堵上了这个漏洞,那自然就更不会在铁路两旁铺上软垫了。

我的意思是,懒的编译器,懒得封堵漏洞,自然更懒得为漏洞搽屁股;好的编译器,没有漏洞,自然不会吐裤子放屁为没有的东西作防范。
#9
ditg2020-06-27 18:57
[b]
比如你把数据保存到磁盘,没执行成功就要排除错误继续尝试保存,而不是不管不顾走人了。
比如你下载文件再处理,“下载文件”是个单独的程序,你执行了“下载文件”但不知道有没有成功,那你继续执行“处理”吗?


程序执行过程中,跟main函数执行到最后的返回值没有任何关系。如果必须以main函数中的某一个动作为例,比如读盘写盘过程,那早期内核在处理时会把进程挂起直到中断结束(下载文件过程类似)。
#10
ditg2020-06-27 19:09
一切 void main 能编译通过的编译器,不是因为编译器允许 void main,而是因为编译器没有堵上 void main 这个漏洞。


如果以是否返回值、或者返回什么值作为判断的唯一标准,有些牵强;强制返回0就不叫漏洞,不返回0就叫漏洞,一个函数的返回值有这么大功效?

我不知道有些现象怎么解释,比如gcc和g++,int main(void)时,没有return 0时gcc出警告(-Wall情况下),但g++表示正常;是否表明C编译器和c++编译器长期以来一直执行着不一样的标准,即使出现问题也不能一概而论?


闲话:您翻一下里奇(C)和本贾(C++)的本人照片对比,不是八卦,面相上是不是可以看出一些编程思想上的差异?
#11
rjsp2020-06-28 08:47
如果以是否返回值、或者返回什么值作为判断的唯一标准,有些牵强;

除了通过返回值来判断是否执行成功,那还有第二种方法吗?难道读取程序的输出?

强制返回0就不叫漏洞,不返回0就叫漏洞,一个函数的返回值有这么大功效?

你理解错了吧,正确的逻辑是 执行成功就应该返回0,执行失败就应该返回非零。
如果不给出正确的返回值,调用者就没法知道程序是否执行成功。

我不知道有些现象怎么解释,比如gcc和g++,int main(void)时,没有return 0时gcc出警告(-Wall情况下),但g++表示正常;是否表明C编译器和c++编译器长期以来一直执行着不一样的标准,即使出现问题也不能一概而论?

不可能的,除非你用的是C99之前的C标准。
在C99之前,没有规定会自动return 0;,那么不写return自然要给出警告。

在古老的C/C++标准中:
int main(void) 和 main(void) 等价;
main函数的任何退出分支必须显式写上 return xxx。

在当今的C/C++标准中:
main(void) 不再合法;
main函数的任何退出分支,若没有显式写上 return xxx,则隐式的 return 0;
#12
ditg2020-06-28 18:38

操作系统:中标麒麟V7.0;    cpu:龙芯3A-2000;    gcc:4.9.3

只有本站会员才能查看附件,请 登录
#13
rjsp2020-06-28 19:18
回复 12楼 ditg
gcc4.9.3 默认使用的是 C90 标准(严格来说是gun89标准,差不多),你可以添加编译参数 -std=c99 让它用新一些的C标准。
gcc5 开始,默认用 C11 标准
gcc8 开始,默认用 C17 标准
最新的gcc发布版本是gcc10
gcc11也可以下载了,但不算稳定。
#14
ditg2020-06-28 19:49
HOSTCFLAGS    = -D__LIBRARY__ -Wall -Wstrict-prototypes -std=c99 -O2 -g -I.
HOSTCC        = gcc


考虑是编译器的问题?
#15
ditg2020-06-28 19:57
另外,我依然不认为void main非法;依然认为shell不会处理非0返回值(因为shell自己都在搞截断,0-255);依然认为除人为设计外,返回任何值都不算错误;依然认为警告并不等于错误。回到前面说的,绝不等于非法。

[此贴子已经被作者于2020-6-28 20:05编辑过]

#16
lin51616782020-06-28 20:15
回复 15楼 ditg
C标准没说非法 各个标准要求略有不用 但至少实现定义
C++中毫无疑问是非法
只有本站会员才能查看附件,请 登录
#17
lin51616782020-06-28 20:15
回复 15楼 ditg
C标准没说非法 各个标准要求略有不用 但至少实现定义
C++中毫无疑问是非法
只有本站会员才能查看附件,请 登录
#18
lin51616782020-06-28 20:18
回复 14楼 ditg
这是一个 程序调用者 编译器 标准 和 程序编写者 多方约定
标准 对其他三者宣称 宿主模式下的C程序的main函数会返回一个 int
标准编译器 按照标准的要求保证 int main 这样的main函数能被正确编译
程序调用者 按照调用C程序会得到一个int返回值这个模式处理C程序
现在到程序编写者 其他人都遵守约定了 就你这胡搞瞎搞 可能不出问题 但出问题就是你本身的责任

可以自己实现一个编译器(教学用 娱乐用 学习用 等等)
对于不是int main 这样的代码按照返回一个Error处理 这样做完全合理


#19
ditg2020-06-28 21:27
好像一直就没C++什么事,反正从我知道的时候就要求必须有返回值,说不准从第一天开始它就这么要求的(感觉本贾啥事都干得出来,呵呵)。

楼上有一句话我很欣赏,出问题就是你本身的责任;虽然自己实力不济,但喜欢这种态度。我喜欢简单,条条框框少一点,编程都玩得快乐些。说实话,虽然自己不会这么写,但找个话题聊聊天也算打发疫情时间,近期着实有点闷。

自己平时喜欢看点内核代码,但进展偏慢,遇到不会的再向几位神级人物讨教,先谢了!
#20
rjsp2020-06-28 21:52
回复 17楼 lin5161678
我用gcc4.9.3测试,
$ gcc prog.c -Wall -Wextra -std=c89 报 warning: return type of 'main' is not 'int' [-Wmain]
$ gcc prog.c -Wall -Wextra -std=c99 报 warning: return type of 'main' is not 'int' [-Wmain]
#21
lin51616782020-06-29 09:22
以下是引用ditg在2020-6-28 21:27:31的发言:

好像一直就没C++什么事,反正从我知道的时候就要求必须有返回值,说不准从第一天开始它就这么要求的(感觉本贾啥事都干得出来,呵呵)。

楼上有一句话我很欣赏,出问题就是你本身的责任;虽然自己实力不济,但喜欢这种态度。我喜欢简单,条条框框少一点,编程都玩得快乐些。说实话,虽然自己不会这么写,但找个话题聊聊天也算打发疫情时间,近期着实有点闷。

自己平时喜欢看点内核代码,但进展偏慢,遇到不会的再向几位神级人物讨教,先谢了!

你搞反了
C++论坛 → 『 C++教室 』 → 这两种语句,C++什么标准?

讲道理应该是没C语言什么事情
提问者想了解的C++相关的内容
如果是其他问题 你混用C回复可能问题不大
刚刚好main这个问题上C/C++态度略有区别
你回答C语言 大体上算是答非所问

#22
lin51616782020-06-29 09:24
以下是引用rjsp在2020-6-28 21:52:19的发言:

我用gcc4.9.3测试,
$ gcc prog.c -Wall -Wextra -std=c89 报 warning: return type of 'main' is not 'int' [-Wmain]
$ gcc prog.c -Wall -Wextra -std=c99 报 warning: return type of 'main' is not 'int' [-Wmain]

看起来你好像回复错了
我知道gcc里面会报告这个warning
这和我的回复也没什么关系呀?
#23
ditg2020-06-29 10:42
我的大意吧,欢迎拍砖……
1.    c++编译器里,是否支持void main()形式?如果支持,我认为本贾有点矛盾,印象里他曾明确表示过这种形式肯定不是c++(顺便评说了一下C,说这种形式即使在C中出现也并不等于说就是C,这是他的个人观点)。
2.    推理c99标准中规定的main形式,应该只有一种int main(),当然参数表述方式可以有不同;至于返回值语句允许不写,交给编译器自动插入。
3.    龙芯cpu下gcc编译C程序出的警告信息,按r版说法是版本执行标准问题,但至少目前可以编译调试通过。
4.    我一直在讨论因程序返回值不确定进而导致的void main形式是否非法,请知悉。
#24
lin51616782020-06-29 11:36
以下是引用ditg在2020-6-29 10:42:10的发言:

我的大意吧,欢迎拍砖……
1.    c++编译器里,是否支持void main()形式?如果支持,我认为本贾有点矛盾,印象里他曾明确表示过这种形式肯定不是c++(顺便评说了一下C,说这种形式即使在C中出现也并不等于说就是C,这是他的个人观点)。
2.    推理c99标准中规定的main形式,应该只有一种int main(),当然参数表述方式可以有不同;至于返回值语句允许不写,交给编译器自动插入。
3.    龙芯cpu下gcc编译C程序出的警告信息,按r版说法是版本执行标准问题,但至少目前可以编译调试通过。
4.    我一直在讨论因程序返回值不确定进而导致的void main形式是否非法,请知悉。

1.
从标准描述和编译器实现来说 C++不支持void main这是事实 至于你说的本贾矛盾不矛盾和这个话题没什么关系 随便他怎么想 现实情况就是C++不支持void main
2.
C99中规定的main的形式 实际上不止限制返回值 还限制参数列表
严格来说 标准保证支持main只有2个形式 int main(void)和int main(int,char**)
其他实现是 实现定义 也就是标准没说不行 但不同编译器可以自由选择支持或者不支持
3.
我从来没说 C语言里面 void main编译不通过
问题是 仅仅是编译通过 这个要求不足以用于说明正确性
4.
void main是否非法 由标准决定
和程序返回值没什么必然联系 程序返回值更多是一个工程应用上的问题 不是决定是否非法的因素

C标准把这个决定权下放到编译器
不同编译器实现上有区别
常见编译器上基本都支持void main这个写法

C++标准直接规定非法

以上讨论仅仅针对宿主模式下的main
独立环境 比如内核编程 比如单片机 等等不适用以上描述

[此贴子已经被作者于2020-6-29 11:37编辑过]

#25
ditg2020-06-29 13:14
1. 好吧,拿一个人说明问题确实不恰当。
2. 想下一份标准看看,好像全要钱,标准具体怎么写的我也不知道。
3. C编译器能编译通过还不够吗?别扩大范围,return 8.5也是可行的,反正结果自己负责。
4. 又回到标准问题了,我还是保留意见,C和C++长期以来可能一直执行着不同的标准,有个c99,也可能还有个c++99;至于怎么看标准,我觉得在C下就是个最低实现,按你的引用,如果想叫C编译器,必须最低实现两种int main形式,其它什么void main、char *envp[]可以叫非标,编译器愿意支持就支持,不愿意支持也没啥,哪怕你支持double main;C++下变成了强制要求,你不写int main就不行,写其它的就算错。我觉得编译器不支持的,统称非法,因为不允许调试通过;返回什么值也不管,自己负责。
#26
lin51616782020-06-29 13:57
以下是引用ditg在2020-6-29 13:14:42的发言:

1. 好吧,拿一个人说明问题确实不恰当。
2. 想下一份标准看看,好像全要钱,标准具体怎么写的我也不知道。
3. C编译器能编译通过还不够吗?别扩大范围,return 8.5也是可行的,反正结果自己负责。
4. 又回到标准问题了,我还是保留意见,C和C++长期以来可能一直执行着不同的标准,有个c99,也可能还有个c++99;至于怎么看标准,我觉得在C下就是个最低实现,按你的引用,如果想叫C编译器,必须最低实现两种int main形式,其它什么void main、char *envp[]可以叫非标,编译器愿意支持就支持,不愿意支持也没啥,哪怕你支持double main;C++下变成了强制要求,你不写int main就不行,写其它的就算错。我觉得编译器不支持的,统称非法,因为不允许调试通过;返回什么值也不管,自己负责。

C编译器能编译通过还不够吗
不够
程序代码:
#include <stdio.h>
int main(int argc, char *argv[])
{
    int n;
    scanf("%d", n);   
    return 0;
}

这样的代码也能编译
不过是错误的代码
#27
ditg2020-06-29 14:49
跟返回值有什么关系?
#28
lin51616782020-06-29 15:04
以下是引用ditg在2020-6-29 14:49:27的发言:

跟返回值有什么关系?

你问 C编译器编译通过还不够吗
这个例子就是在告诉的 编译通过的确还不够咯
void main 这个做法有潜在的出问题的风险
没必要也不应该写void main
写int main 又不会少块肉
没什么理由使用void main
#29
ditg2020-06-29 18:57
scanf("%d", n); 这条语句我认为本身并没有错。你说的是运行结果吗?我不知道你的,我的编译器不同情况下至少会提示段错误或类型错误。

"说实话,虽然自己不会这么写"--引前句
#30
cwa99582020-07-09 15:21
在vs2010 C++里,编译提示错误。
1