我做了一个测试,它出现了这样的事情:
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)
答案 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()函数会内联。
嗯......我又学到了一些东西!谢谢你!