-1

Given the following expression, where A and B stand for arbitrary operands (e.g. local or global variables, values returned by functions, etc.)

A -= B;

Can we always replace this with the following without changing meaning?

(type of A)* temp = &(A);
(*temp) = (*temp) - B;
return (*temp); // implicit

It seems to work, as long as the type of A is not volatile/atomic.

Simple test case:

extern int f (void);
return *f() -= 5;
// is equivalent to
(int)* temp = &(*f()); // single call to function
(*temp) = (*temp) - B;
return (*temp);

Another:

extern int * p;
return p -= 5;
// is equivalent to
(int*)* temp = &(p);
(*temp) = (*temp) - 5; // pointer arithmetic works fine
return (*temp);
mafu
  • 31,798
  • 42
  • 154
  • 247
  • Why make it so complicated? `A -= B` is simply the same as `A = A - B`. – Some programmer dude Feb 03 '18 at 14:04
  • It's downvoted, what is wrong? – mafu Feb 03 '18 at 14:04
  • 1
    @Someprogrammerdude No, replace A with `*f()` – mafu Feb 03 '18 at 14:05
  • 1
    @Someprogrammerdude "The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced." – mafu Feb 03 '18 at 14:15
  • Maybe I'm missing something here, but I assume that `(type of A)* temp = &(A);` is meant to be a a cast. Something that is verified by your code `(int*)* temp = &(p);`. The result of the `*`operator is an lvalue. The result of the cast operator is not an lvalue. Thus `(int*)* temp = &(p);` will not compile. I don't understand why you cast in the first place. – Lundin Feb 05 '18 at 09:43

2 Answers2

1

No.

extern volatile int i;
extern volatile int j;

int f(void) {
    return i += j;
}

int g(void) {
    volatile int *ip = &i;
    *ip = *ip + j;
    return *ip;
}

Compiles to

f:
    movl    j(%rip), %edx
    movl    i(%rip), %eax
    addl    %edx, %eax
    movl    %eax, i(%rip)
    ret

g:
    movl    i(%rip), %eax
    movl    j(%rip), %edx
    addl    %edx, %eax
    movl    %eax, i(%rip)
    movl    i(%rip), %eax
    ret

The number of loads of i is different which can cause different behavior for example if i is used for memory mapped hardware IO.

MuhKarma
  • 705
  • 7
  • 13
  • Ah, I mistook volatile and atomic in the question. This is a good example of how it breaks down, now I'm just looking for one without volatileness. – mafu Feb 03 '18 at 14:10
0

There's no need to make it complicated, it will destroy readability, also this piece of code:

(type of A)* temp = &(A);
(*temp) = (*temp) - B;
return (*temp); // implicit

Will be optimized by the compiler.

GamerH2
  • 55
  • 1
  • 5