Why does * p ++ = * p - a give strange results?

While working with large arrays, I do unsafe pointer calculations, as shown below:

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

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

 [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 is incremented until dereferencing begins. This is correct according to priority rules (++ before *). But now the new value is written to the increased address, and not to the original. Why is this so?

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

In addition, reference to prescriptive rules for pointer types in the C # specification would be highly appreciated. Could not find them so far.

@EDIT: Please note: we are talking about C # here, not C or C ++. Even if I expect the difference is not too big. In addition, as in the example above, I know that the problem can be prevented by increasing the pointer in the next line of code. I want to know why the behavior is also described.

+6
pointers c # operator-precedence
Apr 04 2018-11-11T00:
source share
1 answer

The key is this offer right here:

The pointer is incremented until dereferencing begins. This is correct according to priority rules (++ before *). But now the new value is written to the increased address, and not to the original. Why is this so?

It is understood that you believe that the priority and order of side effects are related. They are not . Side effects occur in order from left to right, period, end of story. if you have

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

then multiplication occurs before addition, because multiplication has a higher priority. And the addition happens before the appointment, because the addition is a higher priority. Side effects A (), B (), C (), and D () occur in order from left to right, regardless of the priority of the operators. The order of execution is not related to priority. (Side effects can occur in a different order if you are observing from a different thread due to processor cache problems, but side effects in one thread are always observed in order from left to right.)

In your example, p++ is on the left right side of *p , so the side effect of p++ occurs before watching the side effect on the right. More specifically, the operation of a variable assignment operator:

  • evaluate the variable address on the left
  • evaluate the right side, converting it to a variable type if necessary
  • save value in variable
  • the result is the value that was saved

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

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

If this topic interests you, see my many articles on the details of the difference between priority, associativity, and order:

http://blogs.msdn.com/b/ericlippert/archive/tags/precedence/

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

What is the difference between i ++ and ++ i?

If you don’t understand how assignment works, and I was surprised to find out that almost no one understands how assignment works - see:

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

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

Other answers indicate that in the C and C ++ programming languages, the language specifications do not indicate in which order the side effects appear if the side effect and its observation are at the same “point in the sequence” as they are here. In C, it is permissible for a side effect of ++ to occur at any time before the end of the statement. After the appointment, before the appointment, whenever at the discretion of the compiler. C # does not allow this kind of lattice. In C #, there is a side effect on the left that occurred by the time the code was executed to the right.

In addition, reference to prescriptive rules for pointer types in the C # specification would be highly appreciated. Could not find them so far.

The spec section you want is 18.5, which reads:

The priority and associativity of unsafe operators is implied by grammar.

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

+15
Apr 04 2018-11-11T00:
source share



All Articles