1
u8 num[] = {0x00, 0x00, 0x40};

u8*ptr = num;

u8 tag;

u16 len;

tag = *ptr++;

len = (u16)*ptr++ <<8 | *ptr++;

I expect len = 0x0040 but len is setted with 0x0000 in visual studio 2013. I don't know why this is occured. Woud you explain with operator precedence viewpoint?

Bhavik Patel
  • 1,044
  • 1
  • 15
  • 33
user1395438
  • 85
  • 1
  • 3
  • 2
    Add some parentheses and you won't need to rely on operator precedence. Problem solved. (although there may be undefined behaviour with ++) – byxor May 24 '17 at 14:20
  • 2
    The answer is simple: Don't write code like that. Write it with parentheses, or separate lines, then let the compiler optimize it. – Chris Rouffer May 24 '17 at 14:23
  • Possible duplicate of [Why are these constructs (using ++) undefined behavior?](https://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior) – n. m. could be an AI May 24 '17 at 16:53
  • 1
    When I compile your code under HP-UX it runs as you expected. This comes down to "implementation-defined behavior", specifically "when is the ++ operator invoked?". VS is apparently not incrementing the pointer until after the statement has completed, which is reasonable as there's no sequence point in the middle of the statement. Conversely, the HP-UX C compiler increments the pointer immediately after each access (apparently - I didn't disassemble the code to check), which is allowed but not required. – Bob Jarvis - Слава Україні May 24 '17 at 17:04
  • 1
    If you write code that is difficult to fathom out when you are writing, it is best to try a different style. Think of the poor person doing maintenance (this could be you) in a few months time – Ed Heal May 25 '17 at 09:48
  • 2
    last line is undefined behaviour (`ptr` written twice without a sequence point) – M.M May 25 '17 at 10:05
  • `len = (u16)*ptr++ <<8 | *ptr++;` Why would you want to write code like that? Even if it weren't undefined behavior, it's hard to understand - at best. Good code is simple, clear, and *easy to understand*. Who's the better coder? The one who goes off into the weeds of the language specification and produces one line of obscure code no one else can understand, or the one who produces the same result in four lines of code a six-year-old can understand? If you can't do the latter, **you don't really understand your programming language nor know how to write code**. – Andrew Henle May 25 '17 at 11:18

1 Answers1

1

Regarding operator precedence, I'd suggest you first take a look to this table.

Now, the ++/-- can be tricky operators because you need to identify whether they're prefix or postfix operators, as you can see in the table if they were prefix ones they'd have the same precedence than * (Dereference).

So, let's analize what's going with your last line len = (u16)*ptr++ <<8 | *ptr++; , there is this set of operators {=, (cast), *(dereference), ++(postfix), <<, |}, so the order of evaluation according to this table would be ++(postfix), *dereference, (type), <<, |, =

That'd be regarding to the order of evaluation, but you need to consider:

Postfix increment/decrement have high precedence, but the actual increment or decrement of the operand is delayed (to be accomplished sometime before the statement completes execution).

That said, here's a couple of ways to achieve what you want:

ptr[1]<<8 | ptr[2]

or:

*(ptr+1) <<8 | *(ptr+2)

One last advice, be careful when you're dealing with operators with the same precedence, as you can see in the table, the associativity could be either left-to-right or right-to-left.

PS: Of course, the asm code generated will depend by the compiler & config used, here's an example of vs2015 in debug mode of that line:

; 7    :     u16 len = (u16)*ptr++ <<8 | *ptr++;

    mov ecx, DWORD PTR _ptr$[ebp]
    movzx   edx, BYTE PTR [ecx]
    shl edx, 8
    mov eax, DWORD PTR _ptr$[ebp]
    movzx   ecx, BYTE PTR [eax]
    or  edx, ecx
    mov WORD PTR _len$[ebp], dx
    mov edx, DWORD PTR _ptr$[ebp]
    add edx, 1
    mov DWORD PTR _ptr$[ebp], edx
    mov eax, DWORD PTR _ptr$[ebp]
    add eax, 1
    mov DWORD PTR _ptr$[ebp], eax

Happy coding.

BPL
  • 9,632
  • 9
  • 59
  • 117
  • Side-effect of `++` is not ordered, and an operand may be evaluated earlier than you give in your list – M.M May 25 '17 at 10:07
  • @M.M Op said he's using visual studio 2013, i've tested and i've referred to that compiler, could you please elaborate what do you mean? – BPL May 25 '17 at 10:20
  • 1
    There does not exist the ordering that you claim (in standard c++). The behaviour you observe on a particular run of vc++ may or may not be replicated on other runs, even with the same compiler – M.M May 25 '17 at 10:30
  • @M.M Edited the answer... could you please provide the link/reference of the c/c++ standard supporting your comment? it'd be cool to add it in order to provide more relevant info about the subject – BPL May 25 '17 at 11:14
  • [See here](https://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior) – M.M May 25 '17 at 11:29