2014-02-08 42 views
3

使问题清晰,我写了一些测试代码:调用函数

#include <stdio.h> 
#include <string.h> 

char *foo(int a) { 
    printf("%d\n", a); 
    static char string[2]; 
    string[0] = a > 0? '1' : '0'; 
    string[1] = '\0'; 
    return string; 
} 

int main(void) { 
    printf("%s\t%s\n", foo(1), foo(0)); 
    return 0; 
} 

运行代码给出了这样的输出:

0 
1 
1  1 

我有这里有两个问题: 1.为什么在1之前打印0?在main的printf函数中,第二个foo会在第一个之前执行?这是一种确定的行为还是偶然的。 2.为什么最终输出1,1?预期的结果应该是1,0

+3

未指定函数参数的评估顺序。 –

+0

@Enrico Granata - 他在问C而不是C++ – Joseph

+0

这将是学习如何使用调试器来遍历代码的好机会。逐步通过可能会让你很清楚发生了什么事情。 –

回答

2

论证评估的顺序是依赖于实现的 - 你的编译器恰好实现它

编辑方式:按你的第二个问题,您使用的是静态缓冲区。这意味着它由两个foo()调用共享 - 即两个foo()调用都返回相同的指针。

根据您的评估订单,首先写入0,然后写入1。在两次foo()调用完成之前,打印缓冲区的时间是1,在这两种情况下(缓冲区静态==共享)。

如果你想解决这个问题,你可以让调用者通过一个缓冲区,你的函数写入用户提供的内存,所以每次调用都是唯一的。

+0

这里更重要的问题实际上是第二个问题 - 为什么是最终结果1,1? – Xufeng

+0

所以'print the string'move实际上是在printf的所有参数都被正确评估之后完成的? – Xufeng

+0

这是函数调用的方式,是的。 –

0

在你的例子中,是否首先调用foo(1)或foo(0)没有在C中定义。在你的情况下调用foo(0),将foo的静态字符串设置为“0”并返回字符串的地址。然后调用foo(1),将字符串设置为“1”。然后你打印字符串两次。无论如何,它永远都是一样的。

+0

好的,我明白了。但是你是否也建议在printf中,在所有参数都被评估之后,两个%s被替换? – Xufeng

+0

它们根本不被替换。该字符串的地址是'printf'函数的参数之一。 'printf'函数扫描该字符串并相应地解释更多的参数。您传入的两个额外参数是foo中静态字符串的地址,因此它们是相同的,并且会打印相同的字符串。 – ooga

+0

因此,编译器首先评估参数,然后打印出整个字符串?因为如果它在打印字符串时即时评估参数,这两个%s应该有不同的值 – Xufeng

0

评估参数的顺序是实现定义:

调用printf后:

printf("%s\t%s\n", foo(1), foo(0)); 

它要求foo()首先用0然后1。在每个呼叫中​​,String的地址被返回并存储在一个变量中。由于Stringstatic,地址不变。通话结束后,来到printf以打印String内容,这是String发生的最后一次更改(在致电foo(1)后)。相同的地址意味着相同的值,意味着输出是:

0 
1 
1  1 
+0

它对函数本身的打印输出顺序很重要 - 前两行。 –

+0

@JoshCaswell是的,我错过了它。 – rullof