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()之前被调用,但是不能保证nfat()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);