1

我做了一个测试,它看起来像这样:

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)
4

3 回答 3

2

[编辑:删除了先前的答案,@Nigel Harper 很礼貌地指出这完全是胡说八道。]

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

由于trim(str, str1)修改了str指向的内存,所以当printf它本身正在执行时,will 指向的内存str已经被修改为包含bcd(显然,trim(str, str1)还有从 will 返回的指针)。

因此,无论计算两个参数的顺序如何,两个输出都是bcd.

于 2013-04-09T23:50:23.270 回答
1

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

于 2013-04-09T23:53:06.067 回答
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() 函数变为内联。

嗯……我又学到东西了!谢谢你!

于 2013-04-09T23:53:39.673 回答