C When division, MSB get set

0

I'm working on a memory address based problem and I found this is very confusing (Below algorithm is mainly calculate the address difference between "Value" and "nv_var.EEStart"):

    ValueI = (int*)(Value);     // ValueI is int*
    EP = (int)(&nv_var.EEStart);            // EP is int
    E = (long)(EP);                         // E is long
    V = (long)(ValueI);                     // V is long
    adr = (V - E) / 2L;                     // adr is long
    printf("Current V: %.8x\n", V);
    printf("Current E: %.8x\n", E);
    printf("V-E    is: %.8x\n", (V - E));
    printf("V-E/2L is: %.8x\n", (V - E) / 2L);
    printf("address is %.8x\n", adr);

Then I got the following output:

Current V: 00439488
Current E: 004391e0
V-E    is: 000002a8
V-E/2L is: 80000154
address is 80000154
Modbuss address:-2147474308

What confused me is my V-E is actually the expected result, but when I divide this number by 2, the result should be 0x00000154, but I got 0x80000154. I'm using gcc compiler without any extra flag, and the expected result should be 0x154.

I can improve it easily by masking off the MSB, but I just wondering why this will happen.

Thanks for all the help.

c
division
asked on Stack Overflow Jun 11, 2020 by Zhiheng Zhang

1 Answer

2

Your program has potential and actual undefined behavior all over the place, but the core problem is likely in part of the code you're not showing: the types of E and V. I suspect they're long. At least (V-E)/2L has type long (or wider), and when you pass that as the argument for a %x format specifier, you get undefined behavior. What's likely happening is that V-E has nonzero bits above bit 31, and your system's implementation of printf (or argument-passing ABI) masks off all the bits outside the size of unsigned int when printing/reading an argument for %x. But after dividing by 2, a nonzero bit 32 has been shifted down to bit 31 and shows in the (UB) printf output.


User contributions licensed under CC BY-SA 3.0