c函数参数评估顺序
我理解不能保证函数的参数将被调用的顺序,但是,如果有一个函数调用作为参数,是不是保证会首先调用该函数?
我帮助学生在实验室进行编程的入门课程,他们应该创建一个递归因子函数,它接收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次调用函数”…
是不是保证如果有一个函数调用作为参数,那么该函数将首先被调用?
不,这不能保证。 没有定义实际参数的评估顺序。 事实上,您的某个参数是评估函数调用的结果,不会改变任何内容。 可以在调用函数之前评估其他参数。
用你的例子:
printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, fat(n, &count), count);
对printf
的调用传递了4个参数。 可以按编译器选择的顺序评估这些参数。
是不是保证如果有一个函数调用作为参数,该函数将首先被调用?
保证在以下呼叫中:
f(g(), h)
在调用f
之前将调用g
。 但是,无法保证在评估h
之前调用g
。
通常,如果您关心首先发生两件事中的哪一件,请将它们放在单独的陈述中。 这样,您就不必记住之前排序的关系,也不必怀疑副作用何时发生。
在您的代码中,printf有4个参数。 必须在输入printf之前评估每个参数,但不指定它们的评估顺序。 编译器利用这一优势来优化代码。
C99§6.5.2.2p10:
函数指示符的评估顺序,实际参数和实际参数中的子表达式是未指定的,但在实际调用之前有一个序列点。
printf("Input: %d. Output: %d.\nFunction called %d times.\n\n", n, fat(n, &count), count);
在这段代码中, fat()
保证在调用printf()之前被调用,但是不能保证n
, fat()
和count
的计算顺序 – count
的值作为printf()
的参数printf()
可以是调用fat()
之前的值,也可以是之后的值。 此外,我认为这是完全未定义的行为,在这种情况下, count
也可以承担绝对任何其他值。
在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);