字符串指针问题

mooniscrazy 2011-01-14 01:33:01
遇到一个问题,非常奇怪。

int main(int argc, char* argv[])
{
char* str="ABC";
//printf("%02x%02x",*str++,*str++);//输出4241,与期待的顺序相反
char c1=*str++;
char c2=*str++;
printf("%02x%02x",c1,c2);//输出4142
}

如果用注释的那行代码打印,结果是4241,但是用现在的代码打印就是4142,顺序相反。百思不得其解。盼大牛帮忙研究,多谢!
...全文
192 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
mooniscrazy 2011-01-14
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 prohibit 的回复:]

多数系统中对函数参数的求值顺序是自右而左的,
printf("%02x%02x\n",(*str1++),(*str1++));
| 1 | | 2 |
//先对2那个位置的*str1求值、即'A'、16进制41,再执行str1++、得*str1 = 'B';
//然后先对1那个位置的*str1求值、即'B'、16进制42,然后再执行st……
[/Quote]
prohibit的解释应该是对的。
跟入栈顺序无关。表达式求职的顺序是从右到左。
结贴。
NowDoIT 2011-01-14
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 mooniscrazy 的回复:]
感谢大家的研究。
这个问题的奇怪之处在于,当放入两个指针++的时候,输出顺序是从右到左的。(实际上这解释不通,跟它的语义不符)
我重新写了一段更简单的代码

char* str1="ABC";
printf("str1:%c%c\n",(*str1++),(*str1++));//输出BA,shit!

char* str2="ABC";
char c1=*str2++;
……
[/Quote]

这个也是木有问题的啊。仔细想想,就明白了.
printf都是从右向左入栈的,最后一个和printf("%c",*str++);没有区别的!
也就是 A; 但是str++了,再跟上一个printf("%c",*str);就会出来B,你可以试试!
mooniscrazy 2011-01-14
  • 打赏
  • 举报
回复
问题在于,为啥有时候从右到左,有时候又是从左到右?
mooniscrazy 2011-01-14
  • 打赏
  • 举报
回复
感谢大家的研究。
这个问题的奇怪之处在于,当放入两个指针++的时候,输出顺序是从右到左的。(实际上这解释不通,跟它的语义不符)
我重新写了一段更简单的代码

char* str1="ABC";
printf("str1:%c%c\n",(*str1++),(*str1++));//输出BA,shit!

char* str2="ABC";
char c1=*str2++;
char c2=*str2++;
printf("str2:%c%c\n",c1,c2);//输出AB

char* str3="ABC";
char b=str3[1];
printf("str3:%c%c",*str3++,b);//输出AB

不仅仅是vc,gcc的结果也是一样。
欣客 2011-01-14
  • 打赏
  • 举报
回复
记住prinf 的函数入栈顺序是从右到左。。输出的顺序是从左到右。
欣客 2011-01-14
  • 打赏
  • 举报
回复
汇编如下,为什么要变成这样的汇编只要问微软了 。
栈的原则是先进后出。

/*****************
printf("%02x%02x",c1,c2);//输出4142
004113D7 movsx eax,byte ptr [c2] // c2 指向 B (后 ++ )
004113DB mov esi,esp
004113DD push eax // b 入栈
004113DE movsx ecx,byte ptr [c1] //c1 指向 A (后 ++ )
004113E2 push ecx // a 入栈
004113E3 push offset string "%02x%02x" (41563Ch)
004113E8 call dword ptr [__imp__printf (4182B8h)]
004113EE add esp,0Ch
004113F1 cmp esi,esp
004113F3 call @ILT+300(__RTC_CheckEsp) (411131h)

现输出A, 后输出B

************************/


/***************************
printf("%02x%02x",*str++,*str++);//输出4241,与期待的顺序相反
00413535 mov eax,dword ptr [str] // A 给eax
00413538 movsx ecx,byte ptr [eax] // A 给 ecx
0041353B mov dword ptr [ebp-0E8h],ecx // A 保存在[ebp-0E8h] 。
00413541 mov edx,dword ptr [str] // A 给 edx
00413544 add edx,1 // str + 1 . 指向 B
00413547 mov dword ptr [str],edx // 覆盖str 的值 ,str 指向B
0041354A mov eax,dword ptr [str] // B 给 eax
0041354D movsx ecx,byte ptr [eax]
00413550 mov dword ptr [ebp-0ECh],ecx // B 值保存在[ebp-0ECh]
00413556 mov edx,dword ptr [str]
00413559 add edx,1
0041355C mov dword ptr [str],edx // str 加 1 指向C
0041355F mov esi,esp
00413561 mov eax,dword ptr [ebp-0E8h] // A 入栈
00413567 push eax
00413568 mov ecx,dword ptr [ebp-0ECh] // B 入栈
0041356E push ecx
0041356F push offset string "%02x%02x" (41563Ch)
00413574 call dword ptr [__imp__printf (4182B8h)]
0041357A add esp,0Ch
0041357D cmp esi,esp
0041357F call @ILT+300(__RTC_CheckEsp) (411131h)

// 先输出B ,输出A
**************************************************/
Jarrys 2011-01-14
  • 打赏
  • 举报
回复
右结合规则
gladstonejay 2011-01-14
  • 打赏
  • 举报
回复
最好别这样输出吧

这样的依赖关系多麻烦
prohibit 2011-01-14
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 prohibit 的回复:]

多数系统中对函数参数的求值顺序是自右而左的,
printf("%02x%02x\n",(*str1++),(*str1++));
| 1 | | 2 |
//先对2那个位置的*str1求值、即'A'、16进制41,再执行str1++、得*str1 = 'B';
//然后先对1那个位置的*str1求值、即'B'、16进制42,然后再执行st……
[/Quote]……格式有点问题,1那个位置是指第一个*str1++,2那个位置是指第二个*str1++
prohibit 2011-01-14
  • 打赏
  • 举报
回复
多数系统中对函数参数的求值顺序是自右而左的,
printf("%02x%02x\n",(*str1++),(*str1++));
| 1 | | 2 |
//先对2那个位置的*str1求值、即'A'、16进制41,再执行str1++、得*str1 = 'B';
//然后先对1那个位置的*str1求值、即'B'、16进制42,然后再执行str1++、得*str1 = 'C';
//输出结果从左往右显示出来即:4241,打不打括号都一样的~~
详细的函数参数求值顺序可以到网上搜一下~~
Trinx 2011-01-14
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 mooniscrazy 的回复:]

感谢大家的解答。不过这个问题还是比较奇怪。
为什么这样两种写法压栈顺序不同?
printf("%02x%02x",c1,c2);//输出4142
printf("%02x%02x\n",(*str1++),(*str1++));//打了括号,为什么还是不能改变求值的顺序?
[/Quote]

printf("%02x%02x\n",(*str1++),(*str1++));这个不同的是后面的*str1++压栈后,str1已经自加1了。
MYMGrub 2011-01-14
  • 打赏
  • 举报
回复
你打了括号但是还是先执行后面的那个处理,后面的那个*str1++处理完了才去处理前面的那个...而你在后面的处理后已经把指针的位置移动了。
mooniscrazy 2011-01-14
  • 打赏
  • 举报
回复
感谢大家的解答。不过这个问题还是比较奇怪。
为什么这样两种写法压栈顺序不同?
printf("%02x%02x",c1,c2);//输出4142
printf("%02x%02x\n",(*str1++),(*str1++));//打了括号,为什么还是不能改变求值的顺序?

prohibit 2011-01-14
  • 打赏
  • 举报
回复
printf("%02x%02x",*str++,*str++);//%02x是指输出至少显示两位数,若不足则添0,%x表示是16进制的格式,'A'的ASCII用16进制表示是41,'B'是42,由于压栈顺序的原因,所以先是显示'B'、再'A'
mooniscrazy 2011-01-14
  • 打赏
  • 举报
回复
printf("%02x%02x\n",(*str1++),(*str1++));
我改成这样写了,结果还是4241。
無_1024 2011-01-14
  • 打赏
  • 举报
回复
跟printf的函数的入栈顺序有关
bdmh 2011-01-14
  • 打赏
  • 举报
回复
printf,先压栈后面的*str++,完后执行++,在压栈前一个*str++,此时str已经移动一个位置了,所以,相当于 printf(...,B,A),这样显示时就是4241了
Trinx 2011-01-14
  • 打赏
  • 举报
回复
下面的打印楼主应该明白吧,至于这个printf("%02x%02x",*str++,*str++);//输出4241。
原因就在于你的编译器是先执行printf函数最后的那个参数,再执行前面的*str++。
ANSI C规定任何函数的参数执行顺序都是未知的,根据编译器的实现不同而不同。
mooniscrazy 2011-01-14
  • 打赏
  • 举报
回复
printf("%02x%02x",*str++,*str++);//输出4241,与期待的顺序相反
关键是这句为什么输出4241?还是不明白啊。照理应该语义是一样的。
Microsues 2011-01-14
  • 打赏
  • 举报
回复
虽然逗号操作符是左结合,但见<<C++ Primer>>一书 P149:
if(ia[index++] < ia[index]) ,你说先计算左边还是右边呢?
C++语言不能保证从左到右的计算次序,这类表达式的行为没有明确定义!
如果要修饰操作数的值,则不要再统一语句的其他地方使用该操作数
加载更多回复(3)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧