user-0 提问: 小白想请教一个关于C语言指针的问题，大神可不可以指点一下，用的是VS2019

回复:
user: user-1
content: 引用 9 楼 lin5161678 的回复:[quote=引用 7 楼 自信男孩 的回复:] 跟出栈顺序是有关系的，当然也跟入栈舒心有关了。  这两个参数那个先出栈，那个表达式就要先计算了。不然，怎么解释楼主的输出呢？ 哪怕是按照入栈理解你的解释也是错的 两个++ 一个操作p 一个操作某个元素的y 也就是说p只操作1次 也就是说没越界  你按照越界理解才是错误的解释  顺便如果入栈顺序能解释 请你解释#4的结果 [/quote] 第二个结构体，我的测试结果是：4,3 不是4,4 可以查一下传参，对于参数是表达式的是传表达式还是传值。参数传递是传值吧，怎么传值呢，必然先计算；所以printf打印之前是先把值计算出来再穿进去了，既然这样跟入参的顺序是有关系的～

user: user-2
content: 引用 7 楼 自信男孩 的回复:跟出栈顺序是有关系的，当然也跟入栈舒心有关了。  这两个参数那个先出栈，那个表达式就要先计算了。不然，怎么解释楼主的输出呢？ 哪怕是按照入栈理解你的解释也是错的 两个++ 一个操作p 一个操作某个元素的y 也就是说p只操作1次 也就是说没越界  你按照越界理解才是错误的解释  顺便如果入栈顺序能解释 请你解释#4的结果

user: user-1
content: 引用 5 楼 lin5161678 的回复:[quote=引用 3 楼 自信男孩的回复:]函数调用，要把参数入栈，一般参数入栈是从左向右依次入栈的，因此出栈就是从右向左了，最后一个参数先出栈，也就是最后一个参数表达式先计算，这样可以解释第一个输出为什么是3,1；后面的一个是1；但是对于3这个输出是随机的，因为p指向的内容已经是越界了～ 这是常见误解 入栈顺序和这个错误无关 这里出现错误是求值无序 而求值顺序和入栈顺序没有必然联系[/quote] 跟出栈顺序是有关系的，当然也跟入栈舒心有关了。  这两个参数那个先出栈，那个表达式就要先计算了。不然，怎么解释楼主的输出呢？

user: user-3
content: ----------------------------------------------------再试图分析一波 printf("%d,%d", (++p)->y,++p->y); 从结果上看，标准仅规定了在执行printf第一个语句之前。一定会完成【对p的自增】以及【对p中y的自增】两个副作用 但并没有明确具体时间与具体顺序。 乍一看两个自增副作用是彼此独立的。但实际上是存在相互影响的可能的

user: user-1
content: 引用 19 楼 lin5161678 的回复:[quote=引用 18 楼 自信男孩 的回复:] 这个结果跟入栈参数的顺序有关系 没看懂吗  入栈是从右到左 但计算顺序和这个没关系 (++p)->y 他可以计算++p 后面不计算->y 而是求值另一个参数 中间的参数求值完成 再把最后的参数的 ->y处理完 这个求值顺序你说和入栈顺序有关系? 这不是胡扯么  [/quote] 我的想法是入栈顺序决定了计算顺序，你的理论是跟入栈没关系，先计算后入栈（我是赞同的，但是先计算哪个实参的问题，先计算那个实参，会导致p的指向指向那个结构元素问题）

user: user-1
content: 引用 21 楼 千梦一生 的回复:不过非要去讨论他是怎么算出这些答案的实属浪费时间。 正常人正常情况不会写出也不会遇到这样的写法。  如同讨论空气。 探讨就有探讨的价值，不是讨论空气。通过探讨希望能注意到更多的问题和知识点～

user: user-3
content: 不过非要去讨论他是怎么算出这些答案的实属浪费时间。 正常人正常情况不会写出也不会遇到这样的写法。  如同讨论空气。

user: user-3
content: printf("%d,%d", ++p->y,(++p)->y); 这个地方的结果 4，4 只能想到一种顺序可能： <1>【p自增副作用完成】p指向第二个元素 <2>【p.y自增副作用完成】p.y变成4 <3>++p->y这个表达式的值作为参数入栈 <4>p->y这个表达式的值作为参数入栈 <5>call printf  <3><4>操作决定的入栈顺序也许可以交换，不过在这里实际没有区别。 所以<1><2><3><4>可以是（如果不考虑入栈顺序的前提之下）任何顺序进行。 ----------------------------------------------------------------------------------------------------------  这里有个重要的地方在于，一个容易忽略的概念： b = 1; a = ++b;  a获得的是等号右边表达式++b的值：在理论上是属于临时的，为'='操作符而生的临时变量。 而表达式++b的值仅仅是 2。 而 b的自增只保证在分号之前，和上一个分号之后。仍和时候去处理。任何时候，所以虽然是前置自增。但即便是在a赋值完毕之后b才自增完毕也是符合约定的。 ------------------------------------------------------------------------------------------------------------ func(b++); 这种我认为也是同理

user: user-2
content: 引用 18 楼 自信男孩 的回复:这个结果跟入栈参数的顺序有关系 没看懂吗  入栈是从右到左 但计算顺序和这个没关系 (++p)->y 他可以计算++p 后面不计算->y 而是求值另一个参数 中间的参数求值完成 再把最后的参数的 ->y处理完 这个求值顺序你说和入栈顺序有关系? 这不是胡扯么

user: user-1
content: 引用 16 楼 lin5161678 的回复:[quote=引用 13 楼 自信男孩 的回复:] 对于楼主的结果，你的解释是什么？  你可以看到这个是从右到左传递参数的 但是结果是4 4  001C39D0  mov         eax,dword ptr [p]   001C39D3  add         eax,8  这个是++p 001C39D6  mov         dword ptr [p],eax   001C39D9  mov         ecx,dword ptr [p]   001C39DC  mov         edx,dword ptr [ecx+4]   001C39DF  add         edx,1  p存到寄存器eax 后+4是取结构体的y 然后add 1 这一段是计算 ++p->y  看到了么 (++p)->y 编译器可以就算一半 就去算++p->y 回头再计算 最后的参数的->y   并且 直到此刻 全部参数都没开始入栈 入栈顺序和求值毫无关系  都求值完了 再入栈也是完全合理的 [/quote] 我明白了，这个4是3+1得到的。++p->y这个++是对y而言的，不是p的++。  根据从右向左入栈，(++p)->y这个是p指向了第二个元素地址，这样传入的y是3。++p->y，因为p已经指向了第二个结构体元素，因此++p->y是对y的+1，因此得到的是4.  这是我的LInux下的编译和运行结果。所以我们的讨论还是在相同编译器下，不然讨论没有意义。  这个结果跟入栈参数的顺序有关系

user: user-1
content: 我是在LINUX编译运行的。另外，这个4是怎么回事？不是越界导致的？你的解释这个4是合理的吗？ss数组里没有4这个初始化项呢  引用 16 楼 lin5161678 的回复:[quote=引用 13 楼 自信男孩 的回复:] 对于楼主的结果，你的解释是什么？  你可以看到这个是从右到左传递参数的 但是结果是4 4  001C39D0  mov         eax,dword ptr [p]   001C39D3  add         eax,8  这个是++p 001C39D6  mov         dword ptr [p],eax   001C39D9  mov         ecx,dword ptr [p]   001C39DC  mov         edx,dword ptr [ecx+4]   001C39DF  add         edx,1  p存到寄存器eax 后+4是取结构体的y 然后add 1 这一段是计算 ++p->y  看到了么 (++p)->y 编译器可以就算一半 就去算++p->y 回头再计算 最后的参数的->y   并且 直到此刻 全部参数都没开始入栈 入栈顺序和求值毫无关系  都求值完了 再入栈也是完全合理的 [/quote]

user: user-2
content: 引用 13 楼 自信男孩 的回复:对于楼主的结果，你的解释是什么？  你可以看到这个是从右到左传递参数的 但是结果是4 4  001C39D0  mov         eax,dword ptr [p]   001C39D3  add         eax,8   这个是++p 001C39D6  mov         dword ptr [p],eax   001C39D9  mov         ecx,dword ptr [p]   001C39DC  mov         edx,dword ptr [ecx+4]   001C39DF  add         edx,1   p存到寄存器eax 后+4是取结构体的y 然后add 1 这一段是计算 ++p->y  看到了么 (++p)->y 编译器可以就算一半 就去算++p->y 回头再计算 最后的参数的->y   并且 直到此刻 全部参数都没开始入栈 入栈顺序和求值毫无关系  都求值完了 再入栈也是完全合理的

user: user-1
content: 引用 14 楼 lin5161678 的回复:[quote=引用 13 楼 自信男孩 的回复:] 咱们还是基于固定的编译器来谈吧，你的连接打不开。编译器不同，传参的顺序可能不一样，基于相同的编译器来分析比较合适～  对于楼主的结果，你的解释是什么？ 你不把传参顺序和求值顺序混为一谈 你会发现想怎么解释就怎么解释[/quote]  传参顺序解决定了p的指向问题。  你解释一下楼主的结果是什么原因吧～

user: user-2
content: 引用 13 楼 自信男孩 的回复:咱们还是基于固定的编译器来谈吧，你的连接打不开。编译器不同，传参的顺序可能不一样，基于相同的编译器来分析比较合适～  对于楼主的结果，你的解释是什么？ 你不把传参顺序和求值顺序混为一谈 你会发现想怎么解释就怎么解释

user: user-1
content: 引用 12 楼 lin5161678 的回复:[quote=引用 10 楼 自信男孩的回复:][quote=引用 9 楼 lin5161678 的回复:][quote=引用 7 楼 自信男孩 的回复:] 跟出栈顺序是有关系的，当然也跟入栈舒心有关了。  这两个参数那个先出栈，那个表达式就要先计算了。不然，怎么解释楼主的输出呢？ 哪怕是按照入栈理解你的解释也是错的 两个++ 一个操作p 一个操作某个元素的y 也就是说p只操作1次 也就是说没越界  你按照越界理解才是错误的解释  顺便如果入栈顺序能解释 请你解释#4的结果 [/quote] 第二个结构体，我的测试结果是：4,3 不是4,4 可以查一下传参，对于参数是表达式的是传表达式还是传值。参数传递是传值吧，怎么传值呢，必然先计算；所以printf打印之前是先把值计算出来再穿进去了，既然这样跟入参的顺序是有关系的～[/quote] https://ideone.com/zADGup 这是一个在线编译器的运行结果 请按照你的理论解释解释[/quote] 咱们还是基于固定的编译器来谈吧，你的连接打不开。编译器不同，传参的顺序可能不一样，基于相同的编译器来分析比较合适～  对于楼主的结果，你的解释是什么？

user: user-2
content: 引用 10 楼 自信男孩的回复:[quote=引用 9 楼 lin5161678 的回复:][quote=引用 7 楼 自信男孩 的回复:] 跟出栈顺序是有关系的，当然也跟入栈舒心有关了。  这两个参数那个先出栈，那个表达式就要先计算了。不然，怎么解释楼主的输出呢？ 哪怕是按照入栈理解你的解释也是错的 两个++ 一个操作p 一个操作某个元素的y 也就是说p只操作1次 也就是说没越界  你按照越界理解才是错误的解释  顺便如果入栈顺序能解释 请你解释#4的结果 [/quote] 第二个结构体，我的测试结果是：4,3 不是4,4 可以查一下传参，对于参数是表达式的是传表达式还是传值。参数传递是传值吧，怎么传值呢，必然先计算；所以printf打印之前是先把值计算出来再穿进去了，既然这样跟入参的顺序是有关系的～[/quote] https://ideone.com/zADGup 这是一个在线编译器的运行结果 请按照你的理论解释解释

user: user-2
content: 引用 10 楼 自信男孩的回复:[quote=引用 9 楼 lin5161678 的回复:][quote=引用 7 楼 自信男孩 的回复:] 跟出栈顺序是有关系的，当然也跟入栈舒心有关了。  这两个参数那个先出栈，那个表达式就要先计算了。不然，怎么解释楼主的输出呢？ 哪怕是按照入栈理解你的解释也是错的 两个++ 一个操作p 一个操作某个元素的y 也就是说p只操作1次 也就是说没越界  你按照越界理解才是错误的解释  顺便如果入栈顺序能解释 请你解释#4的结果 [/quote] 第二个结构体，我的测试结果是：4,3 不是4,4 可以查一下传参，对于参数是表达式的是传表达式还是传值。参数传递是传值吧，怎么传值呢，必然先计算；所以printf打印之前是先把值计算出来再穿进去了，既然这样跟入参的顺序是有关系的～[/quote] 你测试结果就是测试结果 其他人测试结果就不算？ 为什么

user: user-1
content: 函数调用，要把参数入栈，一般参数入栈是从左向右依次入栈的，因此出栈就是从右向左了，最后一个参数先出栈，也就是最后一个参数表达式先计算，这样可以解释第一个输出为什么是3,1；后面的一个是1；但是对于3这个输出是随机的，因为p指向的内容已经是越界了～

user: user-2
content: 未定义行为 结果没意义 不用讨论结果 更重要的是了解什么是未定义行为并避免写出这样的代码

user: user-2
content: 引用 3 楼 自信男孩的回复:函数调用，要把参数入栈，一般参数入栈是从左向右依次入栈的，因此出栈就是从右向左了，最后一个参数先出栈，也就是最后一个参数表达式先计算，这样可以解释第一个输出为什么是3,1；后面的一个是1；但是对于3这个输出是随机的，因为p指向的内容已经是越界了～ 这是常见误解 入栈顺序和这个错误无关 这里出现错误是求值无序 而求值顺序和入栈顺序没有必然联系