代码之家  ›  专栏  ›  技术社区  ›  dreamcrash

此输出背后的原因

  •  1
  • dreamcrash  · 技术社区  · 11 年前

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

    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 回复  |  直到 11 年前
        1
  •  2
  •   Jerry Coffin    11 年前

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

    的论点 printf (所有参数)在执行之前以某种未指定的顺序进行求值 输出函数 它本身就开始了。因此,到那时 输出函数 开始执行,两者 str 以及(重要的) trim(str, str1) 已经过评估。

    修剪(str,str1) 修改内存 字符串 点,按时间 输出函数 本身正在执行,指向的内存 字符串 将被修改为包含 bcd (很明显,指针从 修剪(str,str1) 也会)。

    因此,无论两个参数的求值顺序如何,两个输出都将 立方厘米 .

        2
  •  1
  •   unxnut    11 年前

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

        3
  •  0
  •   TrueY    11 年前

    最后一个论点是 先评估,然后 先推到堆栈中。但评估这些论点的顺序并不明确。

    我输入了一个简单的代码:

    #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()函数变为内联函数。

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