我有一个函数,该函数以char数组的形式进行数学运算,并返回一个int结果(这全部有效,并且仅是出于上下文考虑,与问题无关)。
自然,我的函数定义是:int calc(char * operation){},它期望返回一个int。
在解析字符串以确定操作数和要执行的操作之后,我将结果分配给变量。我只是意识到我忘记了将return语句放入函数中,但是我仍然得到了正确的结果...
这是函数。我本来忘记了最后一行。
// Function to return int results of operation specified in char* (argv[1])
int calc(char* operation)
{
int op_index = 0;
int end_index = 0;
for (int i = 0; i < 128; i ++)
{
if ((operation[i] < 48 || operation[i] > 57) && op_index == 0)
op_index = i;
if (operation[i] == '\0')
{
end_index = i;
i = 128;
}
}
int opa = 0;
int opb = 0;
for (int i = 0; i < op_index; i ++)
opa += (operation[i]-48)*power(10, op_index - (i+1));
for (int i = op_index+1; i < end_index; i ++)
opb += (operation[i]-48)*power(10, end_index - (i+1));
int res = 0;
if (operation[op_index] == '+')
res = opa + opb;
else if (operation[op_index] == '-')
res = opa - opb;
else if (operation[op_index] == '*')
res = opa * opb;
else if (operation[op_index] == '/')
res = opa / opb;
else if (operation[op_index] == '%')
res = opa % opb;
// This is the line that I had forgotten... but still got the right results when calling this function
return res;
}
有人对此有解释吗?我的猜测是,默认情况下它将返回最后一个函数调用的结果,由于最终语句的if / else结构,这将是正确的。
谢谢!
答案 0 :(得分:5)
除main
函数外,任何定义为返回值的函数都必须这样做。如果不是,并且调用函数尝试使用返回的值,则您调用了undefined behavior。
这在C standard的6.9.1p12节中指定:
如果达到了终止函数的
}
,并且 函数调用由调用者使用,其行为是不确定的。
在这种情况下,您“幸运地”知道该程序可以正常工作,但是不能保证总是如此。您的程序看似无关的更改可能会更改未定义行为的显示方式。
答案 1 :(得分:5)
技术上未定义的行为。
如果这是x86 Intel,则可能发生的情况是,从函数返回之前执行的数学运算恰好是在EAX寄存器中保留了预期的返回值。对于返回整数的函数,EAX寄存器也是返回值如何传递回调用方的方法。
calc
函数的尾部已生成如下所示的程序集:
int res = 0;
mov dword ptr [res],0
if (operation[op_index] == '+')
mov eax,dword ptr [operation]
add eax,dword ptr [op_index] // MATH OPERATION WINDS UP IN EAX REGISTER
movsx ecx,byte ptr [eax]
cmp ecx,2Bh
jne calc+149h (05719F9h)
并调用如下代码:
int x;
x = calc((char*)"4+5");
printf("%d\n", x);
生成的程序集是这个
x = calc((char*)"4+5");
push offset string "4+5" (0E87B30h)
call _calc (0E8128Ah)
add esp,4
mov dword ptr [x],eax // TAKE EAX AS RESULT OF FUNCTION AND ASSIGN TO X
但是,当我将项目设置从调试版本切换到优化零售时,所有赌注都关闭了。编译器和链接器将开始内联程序集,进行疯狂的优化等。甚至它甚至会围绕函数未返回任何事实的事实进行优化……事实上,它将在{附近产生一个错误。 {1}}语句抱怨printf
尚未初始化,即使它是根据calc的结果显式分配的。
因此简短的答案是您很幸运。但是我想指出为什么它“恰好起作用”。