#include <stdio.h>
void main()
{
int k = m();
printf("%d", k);
}
void m()
{
printf("hello");
}
输出
hello5
这里返回的void函数是什么?
如果没有printf()则输出为1
。
这里发生了什么?
答案 0 :(得分:7)
void
函数不会返回任何内容。您的程序调用未定义的行为,因为它隐式定义m
以返回类型int
(在C89中,如果函数在声明之前被调用,则隐式假定它具有返回类型int
) ,然后使用返回类型void
定义它。
如果为m
添加前向声明,编译器会正确地抱怨你正在尝试使用void函数的返回值,这是不可能的。
答案 1 :(得分:4)
在这两种情况下(void m
,调用者期望int
,void main
,调用者在C库期望int
),这是未定义的行为,并且您的编译器应该把你弄掉,比如说[GCC 4.8 with -Wall]:
test.c:3:6: warning: return type of ‘main’ is not ‘int’
void main()
^
test.c: In function ‘main’:
test.c:7:5: warning: implicit declaration of function ‘m’
int k = m();
^
test.c: At top level:
test.c:13:6: warning: conflicting types for ‘m’
void m()
^
test.c:7:13: note: previous implicit declaration of ‘m’ was here
int k = m();
^
“隐式声明”的存在仅仅是为了与C1989之前的程序向后兼容,这些程序在此时已超过20年。如果你用更现代的风格编写了这段代码,你就会遇到一个很难的错误:
#include <stdio.h>
extern void m(void);
int main(void)
{
int k = m();
printf("%d", k);
return 0;
}
void m(void)
{
printf("hello");
}
⇒
test.c: In function ‘main’:
test.c:7:13: error: void value not ignored as it ought to be
int k = m();
^
关键的补充是extern void m(void);
行。在检查m
错误时,不允许编译器查看main
的定义,因此您需要一个前向声明来告诉它m
的类型是什么。您还应该知道在C(但不是C ++)中,void m()
表示“m
需要未指定数量的参数”。要声明一个函数采用 no 参数,这就是你想要的,你必须写void m(void)
。
我相信你的特定系统正在发生的事情是你的代码正式忽略的printf
的返回值被留在返回值寄存器中,因此被解释为{{1的返回值但是你不能依赖任何可预测的事情。这就是“未定义的行为”的含义。
答案 2 :(得分:2)
这是未定义的行为。
编译器允许您进行分配的原因是没有m
可用的原型。发生这种情况时,C标准表示该函数必须返回int
。因为在这种情况下实际的函数返回类型是void
,所以行为是未定义的。您在变量k
中获得的值完全是任意的。
答案 3 :(得分:1)
函数的返回值通常存储在一个CPU寄存器EAX for x86中。作为C它只是一个友好的汇编程序,您始终可以从寄存器中读取值。你会得到那里的一切。有效地,int k = m()告诉程序将寄存器EAX的值存储在变量k中。
答案 4 :(得分:0)
在void m();
中调用之前,您尚未声明main
。
某些编译器假定未知函数符号的返回类型为int
(当然在编译时未知)。实际上,您的编译器可能已就此发出了编译警告。
如果您在 main
之前声明此功能(声明应该),那么您可能会收到编译错误。