这个输出背后的原因

时间:2013-04-09 23:45:46

标签: c printf

我做了一个测试,它出现了这样的事情:

char* trim(char* strr, char* str1) {
  char* s = strr;
  while(*str1 == 32) str1++;
  while( (*str1 != 32) && (*str1 != 0) )
        *s++ = *str1++;
  *s = 0;
  return strr;
  }

int main(void) {
  char str[20] = "???";
  char str1[20] ="    bcd  \0";

  printf("(%s)\n(%s)\n", str, trim(str, str1));
  return(0);
}

问题是:上面的代码会打印什么,为什么?我得到了关于输出的线索以及为什么,但我希望听到更多有经验的人关于这个主题。

乍一看它看起来会打印出来:

(???)
(bcd)

但实际上产生的输出是:

(bcd)
(bcd)

3 个答案:

答案 0 :(得分:2)

[编辑:删除了之前的回答,其中@Nigel Harper非常善于礼貌地指出完全是胡说八道。]

printf本身开始执行之前,printf(所有参数)的参数以某种未指定的顺序进行评估。因此,在printf开始执行时,str和(重要)trim(str, str1)都已经过评估。

由于trim(str, str1)修改了str指向的内存,在printf本身执行的时间内,str指向的内存将被修改为包含bcd(很明显,从trim(str, str1)返回的指针也是如此)。

因此,无论评估两个参数的顺序如何,两个输出都将为bcd

答案 1 :(得分:1)

你正在覆盖你的电话中的str函数中的strr。由于它是通过引用传递的,因此更改将反映回调用函数。 printf将获得str的计算副本(在两个参数中都相同)。

答案 2 :(得分:0)

最后一个参数是首先计算,首先推送到堆栈。但是评估论证的顺序并不确定。

我创建了一个简单的代码:

#include <stdio.h>

char *go(char *s) { *s = '0'; return s; }

int main() {
    char str[] = "xyz", str1[] = "abc";
    printf("(%s)(%s)\n", str, go(str));
    printf("(%s)(%s)\n", go(str1), str1);
}

输出:

(0yz)(0yz)
(0bc)(0bc)

您可以使用此gcc命令行分析程序集输出:

gcc -c -g -Wa,-a,-ad x.c >x.lst

如果添加-O2,则顺序相同,但go()函数会内联。

嗯......我又学到了一些东西!谢谢你!