鱼C论坛

 找回密码
 立即注册
查看: 15873|回复: 45

[知识点备忘] S1E16:拾遗

[复制链接]
发表于 2016-3-10 20:59:49 | 显示全部楼层 |阅读模式
购买主题 已有 25 人购买  本主题需向作者支付 5 鱼币 才能浏览
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-3-28 18:57:13 | 显示全部楼层
本帖最后由 rowang 于 2016-3-28 19:16 编辑

小甲鱼老师,我认为关于++运算符那儿说的可能有些不恰当。
i++是先增加变量的值,然后引用原来的值。
具体请参考以下程序:

  1. #include <stdio.h>

  2. int n;

  3. inline void print(int x){
  4.     printf("Now n = %d, x = %d.", n, x);
  5. }

  6. int main(void){
  7.     n = 0;
  8.     print(n++);

  9.     return 0;
  10. }
复制代码

输出是 Now n = 1, x = 0.

供参考,如有问题还请指正^_^。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 0 反对 9

使用道具 举报

 楼主| 发表于 2016-3-29 16:11:47 | 显示全部楼层
rowang 发表于 2016-3-28 18:57
小甲鱼老师,我认为关于++运算符那儿说的可能有些不恰当。
i++是先增加变量的值,然后引用原来的值。
具 ...


先扔个 C99 标准定定心

C99 6.5.2.4 Post&#64257;x increment and decrement operators
……
2. The result of the post&#64257;x ++ operator is the value of the operand. After the result is obtained, the value of the operand is incremented. (That is, the value 1 of the appropriate type is added to it.) See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The side effect of updating the stored value of the operand shall occur between the previous and the next sequence point.

标准已经说得很清楚了:“The result of the post&#64257;x ++ operator is the value of the operand. After the result is obtained, the value of the operand is incremented. (That is, the value 1 of the appropriate type is added to it.)”

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-3-29 16:22:23 | 显示全部楼层
然后解释下你这个程序的实现:

rowang 发表于 2016-3-28 18:57
小甲鱼老师,我认为关于++运算符那儿说的可能有些不恰当。
i++是先增加变量的值,然后引用原来的值。
具 ...

  1. #include <stdio.h>

  2. int n;

  3. inline void print(int x){
  4.     printf("Now n = %d, x = %d.", n, x);
  5. }

  6. int main(void){
  7.     n = 0;
  8.     print(n++);

  9.     return 0;
  10. }
复制代码


由于使用了内联函数,所以该程序可以看成是酱紫:
  1. #include <stdio.h>

  2. int n;

  3. inline void print(int x){
  4.     printf("Now n = %d, x = %d.", n, x);
  5. }

  6. int main(void){
  7.     n = 0;
  8.     printf("Now n = %d, x = %d.", n, n++);

  9.     return 0;
  10. }
复制代码


调用 printf() 函数的时候,入栈顺序是自右向左,因此先执行右边的 n++,由于 ++ 在后是先引用 n 本身的值再自增,因此 x = 0,然后 n 的值自增为 1,到左边再次引用 n 的时候,打印 n = 1。

然后这个程序还有个问题,为了不使内联函数打印 n 报错,你定义多了一个全局变量 n,跟局部变量冲突……(当然这不影响实验结果)。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2016-3-29 22:28:36 | 显示全部楼层
本帖最后由 rowang 于 2016-3-29 22:30 编辑

小甲鱼老师,可是看来并不是内联函数的问题哦,因为把inline去掉后实验结果是一样滴,内联函数只是习惯了打的而已啦(囧),如果使用宏函数的话,确实是会像您解释的那样,而内联函数应该是没有宏函数一样的意想不到的副作用的,这不也是内联函数设计的初衷么?

还有我的程序中并没有局部变量哦,只有一个全局变量n,使用全局变量就是为了观察 将n的值加一 和 将0传递给print(x)函数 这两个事件发生的先后顺序。

然而C99标准在这儿,确实让人没话说呢,求解释...

PS: 未必能及时回消息, 还请原谅哈
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-3-30 01:24:38 | 显示全部楼层
rowang 发表于 2016-3-29 22:28
小甲鱼老师,可是看来并不是内联函数的问题哦,因为把inline去掉后实验结果是一样滴,内联函数只是习惯了打 ...

看错了,看成了 main 中的 int n = 0 了……

这里我说内联函数只是为下边还原作解释哈,C 的函数调用,默认参数都是自右向左进栈的。

另外这个程序也是证明 n 是先使用原来的值再递增的丫:

你看,n++ 作为实参传递给形参 x(这里是对 n 的引用),x 拿到的是 0 而不是 1,然后再打印 n 的值(因为前边已经引用过了,所以 n 当然会自增 1)。

其实检测 n++ 是先使用 n 的值还是递增后再使用 n 的值,只需这样:

  1. #include <stdio.h>

  2. int main()
  3. {
  4.         int n = 0;

  5.         printf("n1 = %d\n", n++);
  6.         printf("n2 = %d\n", n);

  7.         return 0;
  8. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-3-30 19:21:21 | 显示全部楼层
本帖最后由 rowang 于 2016-3-30 19:26 编辑

还是没能说服我QwQ,于是反汇编看了一下。

我的本意是考虑以下三件事情的发生顺序:

1.  将n加一
2.  将0传递给print()函数(压栈)
3.  调用print()函数

不明白的是 n++ 是先使用n的值,"然后"再将n加一,这个所谓的"然后"究竟是发生在什么时候,是发生在调用print(x)前还是print(x)返回后。

于是带着疑问,我查看了反汇编代码,见图:
asm.png
可以看到,print(n++)的实现过程是,将原来n的值保存到eax中,然后借助edx对n进行了加一的操作,然后将eax中保存的原来的值传递给print(x)函数并调用之。

从这个意义上说,n++的确是先保存原来的值,然后对原变量进行加一操作,再然后使用之前保存的原来的值参与运算。

注意我没有说是先使用n的值哦,我说的是先加一然后引用原来的值咯。

大概就这样啦。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2016-3-31 00:44:21 | 显示全部楼层
rowang 发表于 2016-3-30 19:21
还是没能说服我QwQ,于是反汇编看了一下。

我的本意是考虑以下三件事情的发生顺序:


这样吧,你可以把 n++ 理解为 n; n += 1; 两个语句(或者说一个语句分两步操作)。如果遇到需要使用它的值,那么先使用它的值,如果不需要使用它的值,则将它的值 +1。

作为参数是否需要使用它的值呢?需要的,就是实参传入形参 x = n; 的过程,然后 n += 1。

So,x = 0, n = 1。

然后回答“然后”是发生在什么时候,是发生 print() 函数调用之前,inc edx 的时候嘛,下一条语句就把加 1 的结果存回全局变量里了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2016-7-24 16:42:08 | 显示全部楼层
好深奥复杂。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-9-3 21:43:03 | 显示全部楼层
自增自减运算符优先级不是高于赋值运算符么,不应该先算++  -- 再赋值么……
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-11-24 21:30:56 | 显示全部楼层
我看到两个大神在掐架,然后我们一群小白膜拜的眼神ing……
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 6 反对 0

使用道具 举报

发表于 2016-12-2 11:19:29 | 显示全部楼层
看过了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-2-15 09:21:42 | 显示全部楼层
get it
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-5-4 23:24:50 | 显示全部楼层
重温大学知识
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-9-27 10:02:24 | 显示全部楼层
mark
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-10-11 10:07:59 From FishC Mobile | 显示全部楼层
真心牛逼
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-30 16:01:07 | 显示全部楼层
get daol e
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-11-20 09:29:07 | 显示全部楼层
好好好
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-11-20 21:48:57 | 显示全部楼层
ok
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-17 20:54:30 | 显示全部楼层
NB!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 16:33

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表