小甲鱼 发表于 2016-3-10 20:59:49

已有 25 人购买  本主题需向作者支付 5 鱼币 才能浏览 购买主题

rowang 发表于 2016-3-28 18:57:13

本帖最后由 rowang 于 2016-3-28 19:16 编辑

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

#include <stdio.h>

int n;

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

int main(void){
    n = 0;
    print(n++);

    return 0;
}

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

供参考,如有问题还请指正^_^。

小甲鱼 发表于 2016-3-29 16:11:47

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

先扔个 C99 标准定定心 {:10_339:}

C99 6.5.2.4 Postfix increment and decrement operators
……
2. The result of the postfix ++ 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 postfix ++ 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.)”

小甲鱼 发表于 2016-3-29 16:22:23

然后解释下你这个程序的实现:

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

#include <stdio.h>

int n;

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

int main(void){
    n = 0;
    print(n++);

    return 0;
}

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

int n;

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

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

    return 0;
}


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

然后这个程序还有个问题,为了不使内联函数打印 n 报错,你定义多了一个全局变量 n,跟局部变量冲突……(当然这不影响实验结果)。

rowang 发表于 2016-3-29 22:28:36

本帖最后由 rowang 于 2016-3-29 22:30 编辑

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

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

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

PS: 未必能及时回消息, 还请原谅哈

小甲鱼 发表于 2016-3-30 01:24:38

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

{:10_319:} 看错了,看成了 main 中的 int n = 0 了……

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

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

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

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

#include <stdio.h>

int main()
{
      int n = 0;

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

      return 0;
}

rowang 发表于 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)返回后。

于是带着疑问,我查看了反汇编代码,见图:

可以看到,print(n++)的实现过程是,将原来n的值保存到eax中,然后借助edx对n进行了加一的操作,然后将eax中保存的原来的值传递给print(x)函数并调用之。

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

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

大概就这样啦。

小甲鱼 发表于 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 的结果存回全局变量里了。

辛雨之恋 发表于 2016-7-24 16:42:08

好深奥复杂。

MONKID 发表于 2016-9-3 21:43:03

自增自减运算符优先级不是高于赋值运算符么,不应该先算++-- 再赋值么……

穆紫辰 发表于 2016-11-24 21:30:56

我看到两个大神在掐架,然后我们一群小白膜拜的眼神ing……{:10_266:}

hank1016 发表于 2016-12-2 11:19:29

看过了

mhp0114 发表于 2017-2-15 09:21:42

get it

makefile 发表于 2017-5-4 23:24:50

重温大学知识

z578067809 发表于 2017-9-27 10:02:24

mark

1192887012 发表于 2017-10-11 10:07:59

真心牛逼

IMAX鱼油 发表于 2018-5-30 16:01:07

get daol e

Julia999 发表于 2018-11-20 09:29:07

好好好

Mars123456 发表于 2018-11-20 21:48:57

ok

开心丶 发表于 2019-3-17 20:54:30

NB!
页: [1] 2 3
查看完整版本: S1E16:拾遗