C# 为什么*p++;=*p-a给出奇怪的结果?
在使用大型数组时,我会执行不安全的指针计算,如下所示:C# 为什么*p++;=*p-a给出奇怪的结果?,c#,pointers,operator-precedence,C#,Pointers,Operator Precedence,在使用大型数组时,我会执行不安全的指针计算,如下所示: *c++ = *a++ - *b++; 它按预期工作。但对于就地操作,我也需要右侧的c指针: [STAThread] unsafe static void Main(string[] args) { double[] arr = new double[] { 2, 4, 6, 8, 10 }; double scalar = 1; fixed (double* arrP = arr) { dou
*c++ = *a++ - *b++;
它按预期工作。但对于就地操作,我也需要右侧的c指针:
[STAThread]
unsafe static void Main(string[] args) {
double[] arr = new double[] { 2, 4, 6, 8, 10 };
double scalar = 1;
fixed (double* arrP = arr) {
double* end = arrP + arr.Length;
double* p = arrP;
double* p2 = arrP;
while (p < end) {
// gives: 3,5,7,9,2,4827634676971E+209
*p++ = *p - scalar;
// gives correct result: 1,3,5,7,9
//*p = *p - scalar;
//p++;
}
}
Console.WriteLine(String.Join<double>(",", arr));
Console.ReadKey();
}
[STAThread]
不安全的静态void Main(字符串[]args){
double[]arr=新的double[]{2,4,6,8,10};
双标量=1;
固定(双*arrP=arr){
双*端=arrP+arr.长度;
双*p=arrP;
双*p2=arrP;
while(p
指针在取消引用之前递增。根据优先级规则(++before*),这是正确的。但现在新值被写入递增的地址,而不是原始地址。为什么会这样
我发现这样的问题:。但它只处理右侧的*c++表达式。为什么写访问与读访问不同
此外,如果能链接到C#规范中指针类型的前置规则,我们将不胜感激。到目前为止找不到他们
编辑:请注意,这里我们讨论的是C,而不是C或C++。即使我预计这里的差异不会太大。另外,就像上面的例子一样,我知道,可以通过在下一个代码行中增加指针来防止这个问题。我想知道,为什么这种行为会如此 关键是这句话: 指针在取消引用之前递增根据优先规则(++before*),这是正确的。但现在新值被写入递增的地址,而不是原始地址。为什么会这样 这意味着你相信副作用的先后顺序是相关的它们不是。副作用的发生顺序从左到右,周期,故事的结尾。如果你有
A().x = B() + C() * D();
然后乘法发生在加法之前,因为乘法的优先级更高。加法发生在赋值之前,因为加法的优先级更高A()、B()、C()和D()的副作用按从左到右的顺序发生,与运算符的优先级无关。执行顺序与优先级无关。(如果由于处理器缓存问题而从另一个线程进行观察,可能会发现副作用的发生顺序不同,但一个线程中的副作用总是按从左到右的顺序进行观察。)
在您的示例中,p++
位于右侧*p
的左侧,因此p++
的副作用发生在观察右侧副作用之前。更具体地说,赋值运算符对变量的操作是:
- 计算左侧变量的地址
- 计算右侧,必要时将其转换为变量类型
- 将值存储在变量中
- 结果是存储的值
其他的答案指出,在C和C++编程语言中,语言规范没有指明如果副作用和观察结果在同一个“序列点”中出现了什么顺序的副作用,就像它们在这里一样。在C语言中,++的副作用可以在语句结束之前的任何时候发生。赋值后、赋值前,无论何时,由编译器自行决定。C#不允许这种格子。在C#中,在右边的代码执行时,观察到左边的副作用已经发生
此外,如果能链接到C#规范中指针类型的前置规则,我们将不胜感激。到目前为止找不到他们 所需的等级库部分为18.5,其中说明: 语法隐含了不安全运算符的优先级和关联性因此,请阅读语法并将其解决。从阅读附录B第3节中的语法开始。为什么不把它写成两行而不是一行呢?因为它不明显,也不容易阅读,为什么不把它分解成多个语句呢<代码>*p=*p-标量;p++或
*p-=标量;p++
看起来不错吗?它给出了一个奇怪的结果,因为它是一个奇怪的语句。似乎是对的。分成几行将是最后一种存在。代码是更大的代码生成框架的输出。更改代价高昂(但当然可以做到)。没有人愿意提及的是,您可以使用*p=*p++-scalar
或*p++=*p2++-标量代码>--第一个之所以有效,是因为副作用的C#顺序规则,第二个只是利用代码生成框架似乎设置的p2
指针。(当然,除非后者用于您省略的其他内容)。“这有帮助吗?”语法暗示着“我以前才发现这个句子,希望得到一个更具体的短语?”?总之