1
((unsigned long long *)P)[0] += B;

Is the above Statement equivalent to: ((unsigned long long *)P)[0] = ((unsigned long long *)P)[0] + B; ?

P is defined as: int P[5];

B is defined as: unsigned long long B;

Size of int is 2 bytes.

M Sharath Hegde
  • 485
  • 1
  • 6
  • 20
  • 1
    What do you mean by equivalent? Equivalent in the way the instructions are interpreted or what the outcome of assembly code is? The results "in numbers" are the same. – elasticman Sep 12 '18 at 07:42
  • @elasticman The way they are interpreted. Do they both mean the same thing? if they mean the same thing, I assume there won't be any difference in terms of assembly caode. – M Sharath Hegde Sep 12 '18 at 07:47
  • 2
    Note: You are dererencing pointer using the wrong type; that is *strict aliasing violation* and results in *undefined behaviour*. Both statements are invalid in standard C. – user694733 Sep 12 '18 at 08:28
  • To expand on @user694733 comment and noting that in general `sizeof(int) != sizeof(long long int)`, see e.g. https://wandbox.org/permlink/CDb1VB3LcnUQ0DJj – Bob__ Sep 12 '18 at 09:09
  • 2
    To expand on @user694733's comment on strict aliasing, what you are doing is not guaranteed to work. For example, on your system `int` could have a requirement to be aligned on a 2-byte boundary, while `unsigned long long` might have to be on an 8-byte boundary. When you force an `int` to act as the start of an `unsigned long long` value, you violate your system's hardware restriction. If anyone posts "But it worked for me!", they're just showing that they don't understand what they're doing. A lot of people think what you're doing is OK because the common x86 systems mostly allow such code. – Andrew Henle Sep 12 '18 at 10:39
  • @AndrewHenle P is an array of Int, what is wrong if I type cast P as `unsigned long long`? how does it violates system's hardware restriction? – M Sharath Hegde Sep 12 '18 at 11:46
  • *P is an array of Int, what is wrong if I type cast P as `unsigned long long`?* You can't do that because `P` is not an `unsigned long long`. Period. It's called the ["strict aliasing rule"](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) What can happen? [Most of these failures](https://www.google.com/search?q=sparc+SIGBUS) are probably caused by violating the strict aliasing rule on hardware that actually has alignment restrictions on data types. Another example: https://stackoverflow.com/questions/45880782/call-stack-shows-sigbus-what-does-that-mean – Andrew Henle Sep 12 '18 at 12:48
  • See [**6.3.2.3 Pointers**, paragraph 7](https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7): "A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined." – Andrew Henle Sep 12 '18 at 12:55
  • @AndrewHenle There seems to be a small misunderstanding: Strict aliasing violation and alignment issue are not the same thing (although typical errors lead to both). You are right about alignment issues being hardware related. But it's possible to have SA violation even when alignment and size of types match. SA violation makes compiler blind to the changes in variable, so it may fail to insert instructions to refresh data between RAM and CPU register for example. – user694733 Sep 13 '18 at 11:34
  • @user694733 Those were examples in response to the "how does it violates system's hardware restriction?" question a few comments up. A strict aliasing violation without a hardware fault such as a `SIGBUS` could probably be described as "just more normal x86 code", for better or for worse. The examples you mention - "fail to insert instructions to refresh data between RAM and CPU register" - are subtle bugs and hard to find common, clear-cut, and consistently-repeatable examples of, unlike searching for "SIGBUS arm" or "SIGBUS sparc". – Andrew Henle Sep 13 '18 at 11:44

1 Answers1

1

They mean the same and the assembly (for x86-64 systems) is the same as well. You can check this at the godbolt compiler explorer here which shows the assembly of the two statements.

int P[5];
unsigned long long B;

void check1() {
    ((unsigned long long *)P)[0] += B;
}

void check2() {
    ((unsigned long long *)P)[0] = ((unsigned long long *)P)[0] + B;
}

Assembly of check1:

check1:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $P, %eax
        movq    (%rax), %rdx
        movq    B(%rip), %rax
        movl    $P, %ecx
        addq    %rdx, %rax
        movq    %rax, (%rcx)
        nop
        popq    %rbp
        ret

Assembly of check2:

check2:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $P, %eax
        movq    (%rax), %rdx
        movq    B(%rip), %rax
        movl    $P, %ecx
        addq    %rdx, %rax
        movq    %rax, (%rcx)
        nop
        popq    %rbp
        ret
P.W
  • 26,289
  • 6
  • 39
  • 76
  • Given `int P[5];`, `((unsigned long long *)P)[0] += B;` violates strict aliasing and is undefined behavior. Such code will fail on systems that have alignment restrictions on data. Like here: https://stackoverflow.com/questions/19114491/structure-assignment-in-linux-fails-in-arm-but-succeeds-in-x86 – Andrew Henle Sep 12 '18 at 12:52
  • My answer was limited to x86 systems and I have mentioned this in the answer. – P.W Sep 12 '18 at 13:50
  • [It's not guaranteed to work on x86 systems either.](https://stackoverflow.com/questions/15233717/disable-misaligned-data-fixups-on-x86-64-linux) – Andrew Henle Sep 12 '18 at 13:56
  • But would it not require the auto-alignment feature to be OFF for it not to work? – P.W Sep 12 '18 at 14:21