我理解对函数的参数调用的顺序没有保证,但是,如果有一个函数调用作为参数,是不是保证会先调用该函数?
我帮助学生在实验室进行编程的入门课程,他们应该创建一个递归因子函数,它接收n(对于n!)和一个指向整数的指针,该整数将用于计算函数调用和然后他们应该打印结果(n,n!和count)。
许多人抱怨说他们使用指针是错误的,所以我查看了代码,他们都是这样的:
int fat(int n,int *count)
{
(*count)++;
if(n>1)
{
return n * fat(n-1,count);
}
return 1;
}
int main()
{
int n, count=0;
do
{
printf("Write n for fat (n >= 0): ");
scanf("%d", &n);
}while(n<0);
printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, fat(n, &count), count);
printf("%d times\n",count);
return 0;
}
使用gcc编译(Debian 4.7.2-5)4.7.2输出为:
Write n for fat (n >= 0): 4
Input: 4. Output: 24.
Function called 0 times.
4 times
因此,如果胖子应该首先运行,“函数调用...”应该打印“4次调用函数”而不是0。
所以,我的问题是:
即使保证参数中的函数调用将在“接收”之前运行,但仍然不确定它是否在查看非函数调用的参数之前运行?
另一个奇怪的事情是,这个相同的代码在xcode上打印“4次调用函数”...
答案 0 :(得分:2)
是不是保证如果有一个函数调用作为参数,那么将首先调用该函数?
保证在以下呼叫中保证:
f(g(), h)
在调用g
之前将调用 f
。但是,无法保证在评估g
之前调用h
。
通常,如果您关心首先发生两件事中的哪一件,请将它们放在单独的陈述中。这样,您就不必记住之前排序的关系,也不知道何时会出现副作用。
答案 1 :(得分:2)
在您的代码中,printf有4个参数。必须在输入printf之前评估每个参数,但不指定它们的评估顺序。编译器利用这一优势来优化代码。
C99§6.5.2.2p10:
功能指示符的评估顺序,实际 参数和实际参数中的子表达式是 未指定,但在实际调用之前有一个序列点。
答案 2 :(得分:1)
如果有一个函数调用作为参数,是不是可以保证,首先会调用该函数?
不,这不能保证。未定义实际参数的评估顺序。事实上,您的某个参数是评估函数调用的结果,不会改变任何内容。在调用函数之前,可以评估其他参数。
用你的例子:
printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n,
fat(n, &count), count);
对printf
的调用传递了4个参数。可以按编译器选择的顺序评估这些参数。
答案 3 :(得分:1)
printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, fat(n, &count), count);
在此代码中,保证在调用printf()之前调用fat()
,但无法保证n
,fat()
和{{1}的顺序被评估 - count
的值作为count
的参数可以是调用printf()
之前的值,或者它之后的值。此外,我认为这是完全未定义的行为,在这种情况下,fat()
也可以采用绝对任何其他值。
答案 4 :(得分:1)
在C和C ++中都没有这样的保证(例外是C#)。因此,函数调用的参数可以从右到左(通常对于大多数编译器)或从左到右进行评估。函数参数的评估顺序未指定。
很明显,编译器使用它从右到左评估参数。 count首先被avaluated,因此它的值为0.然后编译器评估函数fat的调用,最后它计算n。
要获得正确的结果,您应该将printf语句拆分为两个语句
int rez = fat(n, &count);
printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, rez, count);