*a = *b; a++; b++;
和
*a++ = *b++
是等价的,但这是线路时实际发生的事情
*a++ = *b++
叫做?有人可以澄清编译器如何解释第二行吗?我知道从右到左的优先级等等,但有人可以准确地编写编译器用来解释这行代码的步骤吗?
解决方法@H_301_16@
你说你相信:
*a = *b; a++; b++;
相当于
*a++ = *b++;
但这是错误的,所以你有一个错误的信念.让我们纠正你的错误信念.
在第一种情况下,必须发生以下事情:
> VAR:* a必须进行求值才能生成变量,将其称为var
> VAL:* b必须被评估以产生一个值,称之为val
> ASSIGN:val必须分配给var.
> INCA:必须递增.
> INCB:b必须递增.
对编译器如何排序有什么限制?
> VAR和VAL必须在ASSIGN之前发生.
> ASSIGN必须在INCA之前发生.
> INCA必须在INCB之前发生.
这里的规则是在下一个语句开始之前必须完成一个语句的所有副作用.所以有两个法律排序. VAR VAL ASSIGN INCA INCB,或VAL VAR ASSIGN INCA INCB.
现在让我们考虑第二种情况.
*a++ = *b++;
我们有相同的五个操作,但它们的排序约束完全不同,因为它们都在同一个语句中,所以关于语句的规则不适用.现在的限制是:
> VAR和VAL必须在ASSIGN之前发生.
> VAR的评估必须使用a的原始值
> VAL的评估必须使用b的原始值
请注意,我没有说增量必须在之后发生.相反,我说必须使用原始值.只要使用原始值,增量就可以随时发生.
因此,例如,将其生成为完全合法
var = a;
a = a + 1; // increment a before assign
*var = *b;
b = b + 1; // increment b after assign
这样做也是合法的:
val = *b;
b = b + 1; // increment b before assign
*a = val;
a = a + 1; // increment a after assign
按照您的建议进行操作也是合法的:首先进行分配,然后按从左到右的顺序进行增量.首先进行分配也是合法的,然后以从右到左的顺序进行增量.
C编译器具有广泛的自由度来生成代码,但它喜欢这种表达式.确保这一点在你的脑海中非常明确,因为大多数人都错了:只是因为变量之后并不意味着增量发生得晚.只要编译器确保使用原始值,增量就可以在编译器喜欢的时候发生.
这是C和C的规则.在C#中,语言规范要求赋值左侧的副作用发生在赋值右侧的副作用之前,并且两者都发生在赋值的副作用之前. C#中的相同代码将需要生成为:
var_a = a;
a = a + 1;
// must pointer check var_a here
var_b = b;
b = b + 1;
val = *var_b; // pointer checks var_b
*var_a = val;
“指针检查”是C#要求运行时验证var_a是有效指针的点;换句话说,* var_a实际上是一个变量.如果不是那么它必须在评估b之前抛出异常.
同样,允许C编译器以C#方式执行,但不是必需的.
*a = *b; a++; b++;
相当于
*a++ = *b++;
但这是错误的,所以你有一个错误的信念.让我们纠正你的错误信念.
在第一种情况下,必须发生以下事情:
> VAR:* a必须进行求值才能生成变量,将其称为var
> VAL:* b必须被评估以产生一个值,称之为val
> ASSIGN:val必须分配给var.
> INCA:必须递增.
> INCB:b必须递增.
对编译器如何排序有什么限制?
> VAR和VAL必须在ASSIGN之前发生.
> ASSIGN必须在INCA之前发生.
> INCA必须在INCB之前发生.
这里的规则是在下一个语句开始之前必须完成一个语句的所有副作用.所以有两个法律排序. VAR VAL ASSIGN INCA INCB,或VAL VAR ASSIGN INCA INCB.
现在让我们考虑第二种情况.
*a++ = *b++;
我们有相同的五个操作,但它们的排序约束完全不同,因为它们都在同一个语句中,所以关于语句的规则不适用.现在的限制是:
> VAR和VAL必须在ASSIGN之前发生.
> VAR的评估必须使用a的原始值
> VAL的评估必须使用b的原始值
请注意,我没有说增量必须在之后发生.相反,我说必须使用原始值.只要使用原始值,增量就可以随时发生.
因此,例如,将其生成为完全合法
var = a; a = a + 1; // increment a before assign *var = *b; b = b + 1; // increment b after assign
这样做也是合法的:
val = *b; b = b + 1; // increment b before assign *a = val; a = a + 1; // increment a after assign
按照您的建议进行操作也是合法的:首先进行分配,然后按从左到右的顺序进行增量.首先进行分配也是合法的,然后以从右到左的顺序进行增量.
C编译器具有广泛的自由度来生成代码,但它喜欢这种表达式.确保这一点在你的脑海中非常明确,因为大多数人都错了:只是因为变量之后并不意味着增量发生得晚.只要编译器确保使用原始值,增量就可以在编译器喜欢的时候发生.
这是C和C的规则.在C#中,语言规范要求赋值左侧的副作用发生在赋值右侧的副作用之前,并且两者都发生在赋值的副作用之前. C#中的相同代码将需要生成为:
var_a = a; a = a + 1; // must pointer check var_a here var_b = b; b = b + 1; val = *var_b; // pointer checks var_b *var_a = val;
“指针检查”是C#要求运行时验证var_a是有效指针的点;换句话说,* var_a实际上是一个变量.如果不是那么它必须在评估b之前抛出异常.
同样,允许C编译器以C#方式执行,但不是必需的.