为什么* p ++ = * p-给出奇怪的结果? [英] why does *p++ = *p - a give strange results?

查看:80
本文介绍了为什么* p ++ = * p-给出奇怪的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在处理大型数组时,我正在执行不安全的指针计算,如下所示:

While working with large arrays, I am doing unsafe pointer computations like the following:

*c++ = *a++ - *b++; 

它按预期工作.但是对于就地操作,我也需要在右侧使用c指针:

It works as expected. But for inplace operations, I need the c pointer on the right side as well:

[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(); 
}

在取消引用之前,指针会在 之前递增.根据优先规则(在*之前的++),这是正确的.但是现在,新值写入了递增地址,而不是原始地址.为什么会这样呢?

The pointer gets incremented before the dereference happens. This is correct according to precedence rules (++ before *). But now the new value is written to the incremented address, not to the original. Why is this so?

我发现了这样一个问题:在一个语句中取消引用和前进指针? /a>.但是它仅在右侧处理* c ++表达式.为什么写访问权限与读访问权限不同?

I found this SO question: dereference and advance pointer in one statement? . But it handles the *c++ expression on the right side only. Why would the write access be different from the read access?

此外,在C#规范中指向指针类型的优先规则的链接将受到高度赞赏.到目前为止找不到它们.

Also, a link to the preceedence rules for pointer types in the C# spec would be highly appreciated. Couldn't find them so far.

@请注意,我们在这里谈论的是C#,而不是C或C ++.即使我期望这里的差异不会太大.而且,就像上面的示例一样,我知道,可以通过在下一个代码行中增加指针来防止该问题.我想知道,为什么行为仍然如前所述.

@ Please note, we are talking about C# here, not C or C++. Even if I expect the difference to be not too big here. Also, like in the example above, I know, the problem can be prevented by incrementing the pointer in the next code line. I want to know, why the behaviour is as described anyway.

推荐答案

关键是这句话:

在取消引用之前,指针将递增. 根据优先级规则,这是正确的(*之前的++).但是现在,新值被写入递增的地址,而不是原始值.为什么会这样呢?

The pointer gets incremented before the dereference happens. This is correct according to precedence rules (++ before *). But now the new value is written to the incremented address, not to the original. Why is this so?

含义是,您认为副作用的优先级和顺序是相关的. 不是.副作用发生的顺序为从左到右,时间段,故事结尾.如果有

The implication is that you believe that precedence and order of side effects are related. They are not. Side effects happen in order left to right, period, end of story. If you have

A().x = B() + C() * D();

然后乘法发生在加法之前,因为乘法的优先级更高.并且加法发生在分配之前,因为加法的优先级更高. A(),B(),C()和D()的副作用按从左到右的顺序发生,而与运算符的优先级无关.执行顺序与不相关优先. (由于处理器高速缓存问题,如果您从另一个线程观察,则副作用可能会以不同的顺序发生,但是一个线程中的副作用总是按照从左到右的顺序观察到的.)

then the multiplication happens before the addition, because multiplication is higher precedence. And the addition happens before the assignment because addition is higher precedence. The side effects of A(), B(), C() and D() happen in left-to-right order irrespective of precedence of the operators. Order of execution is unrelated to precedence. (Side effects may be observed to happen in a different order if you are observing from another thread due to processor cache issues, but side effects in one thread are always observed in left-to-right order.)

在您的示例中,p++位于右侧*p左侧,因此p++的副作用发生在之前观察右边的副作用.更具体地说,赋值运算符对变量的运算是:

In your example the p++ is to the left of the right-hand side *p, and therefore the side effect of the p++ happens before the observation of the side effect on the right. More specifically, the operation of the assignment operator to a variable is:

  • 评估左侧变量的地址
  • 评估右侧,如有必要,将其转换为变量的类型
  • 将值存储在变量中
  • 结果是存储的值

第一步-计算左侧变量的地址-++是什么.

The first step -- evaluate the address of the variable on the left -- is what does the ++.

这在C#规范中已明确定义;有关详细信息,请参见关于运算符优先级和执行顺序的部分.

This is clearly defined in the C# spec; see the section on operator precedence and order of execution for details.

如果您对此主题感兴趣,请参阅我的许多文章,详细介绍优先级,关联性和顺序之间的区别:

If this subject interests you, see my numerous articles on the details of the difference between precedence, associativity and order:

http://blogs.msdn.com/b/ericlippert/存档/标签/优先级/

如果您不了解++的工作原理-不幸的是,几乎没人能做到-请参阅以下问题:

If you don't understand how ++ works -- and almost no one does, unfortunately -- see this question:

i ++和++ i?

如果您不了解分配的工作原理,而让我惊讶的是,几乎没人能理解分配的工作原理,请参阅:

If you don't understand how assignment works -- and it has been surprising to me to learn that almost no one does understand how assignment works -- see:

http://blogs.msdn.com/b/ericlippert/archive/tags/simple + assignment/

http://blogs.msdn.com/b/ericlippert/archive/tags/compound + assignment/

其他答案指出,在C和C ++编程语言中,语言规范未指定如果副作用及其观察结果在同一序列点"内,则副作用以什么顺序出现?在这里.在C语言中,允许++的副作用在语句结束之前的任何时间 发生.分配之后,分配之前,编译器可以随时决定. C#不允许这种纬度.在C#中,观察到在执行右侧代码时发生了左侧副作用.

The other answers are pointing out that in the C and C++ programming languages, the language specifications do not specify in what order side effects appear to happen if the side effect and its observation are within the same "sequence point", as they are here. In C it is permissible for the side effect of the ++ to happen at any time before the end of the statement. After the assignment, before the assignment, whenever, at the discretion of the compiler. C# does not permit that sort of lattitude. In C#, a side effect to the left is observed to have happened by the time that code to the right executes.

此外,在C#规范中指向指针类型的优先规则的链接将受到高度赞赏.到目前为止找不到它们.

Also, a link to the preceedence rules for pointer types in the C# spec would be highly appreciated. Couldn't find them so far.

您想要的规格部分为18.5,其中指出:

The spec section you want is 18.5, which states:

语法隐含了不安全运算符的优先级和关联性.

The precedence and associativity of the unsafe operators is implied by the grammar.

因此,请阅读语法并加以解决.首先阅读附录B,第3节中的语法.

So read the grammar and work it out. Start by reading the grammar in Appendix B, section 3.

这篇关于为什么* p ++ = * p-给出奇怪的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆