开发者

Substracting pointers: Where does this missing level of indirection come from?

开发者 https://www.devze.com 2023-01-08 01:34 出处:网络
I\'m having trouble understanding the behavior of the MS VC compiler on this one. This line compiles fine, but the result I get is not 开发者_如何转开发what I\'d expect at all:

I'm having trouble understanding the behavior of the MS VC compiler on this one. This line compiles fine, but the result I get is not 开发者_如何转开发what I'd expect at all:

this->Test((char *)&CS2 - (char *)&CS1 == sizeof(void *));

The CS1 and CS2 arguments are declared as follows:

myFunction(tCS1* CS1, tCS2* CS2) {...

tCS1 and tCS2 are structures containing one int and one __int64, resp.

This is meant to check the distance on the stack between my arguments CS1 and CS2, which are both pointers. When I break execution on this line and use the debugger to get the addresses of my two variables, I find that they indeed are 8 bytes away from each other (x64 platform).

However, the result of the comparison is false.

Here is the assembly code generated by the compiler:

mov         rax,qword ptr [CS1] 
mov         rdi,qword ptr [CS2] 
sub         rdi,rax 

(then it does the comparison using the result stored in rdi, and makes the call)

Yes, the compiler is comparing the values of my pointer arguments, rather than their addresses. I'm missing a level of indirection here, where did it go?

Of course I can't reproduce this in a test environment, and I have no clue where to look anymore. I'm cross-compiling this bit of code on a 32-bits machine to an x64 platform (I have to), that's the only 'odd' thing about it. Any idea, any hint?


The assembly

mov         rax,qword ptr [CS1] 
mov         rdi,qword ptr [CS2] 
sub         rdi,rax

indicates CS1 and CS2 are not really stack arguments, but rather some global symbols - if I wanted to produce similar results, I'd do something like this:

int* CS1 = NULL, *CS2 = NULL; /* or any other value...*/
#define CS1 *CS1
#define CS2 *CS2

Of course this is ugly code - but have you checked you haven't such things in your code? Also, dynamic linker might play a role in it.

And last but not least: If you attempt to write code like:

void foo()
{
  int a;
  int b;
  printf("%d", &a-&b);
}

You should be aware that this is actually undefined behaviour, as C (and C++) only permits to subtract pointers pointing inside a single object (eg. array).


As @jpalacek and commenters observed this is undefined and the compiler may be taking advantage of it to do whatever it likes. It is pretty strange.

This code "works" on gcc:


#include 

int func(int *a, int *b)
{
    return (char *)&a - (char *) &b;
}

int main(void)
{
    int a, b;
    printf("%d", func(&a, &b));
    return 0;
}

(gdb) disassemble func
Dump of assembler code for function func:
   0x0 80483e4 :    push   %ebp
   0x080483e5 : mov    %esp,%ebp
=> 0x080483e7 : lea    0x8(%ebp),%edx
   0x080483ea : lea    0xc(%ebp),%eax
   0x080483ed : mov    %edx,%ecx
   0x080483ef :    sub    %eax,%ecx
   0x080483f1 :    mov    %ecx,%eax
   0x080483f3 :    pop    %ebp
   0x080483f4 :    ret    
End of assembler dump.

and with optimization it just knows their relative addresses:

(edit: answer was truncated here for some reason)

(gdb) disassemble  func
Dump of assembler code for function func:
   0x08048410 : push   %ebp
   0x08048411 : mov    $0xfffffffc,%eax
   0x08048416 : mov    %esp,%ebp
   0x08048418 : pop    %ebp
   0x08048419 : ret    
End of assembler dump.

The interesting thing is that with -O4 optimization it returns +4 and without it, it returns -4.

Why are you trying to do this anyhow? There's no guarantee in general that the arguments have any memory address: they may be passed in registers.

0

精彩评论

暂无评论...
验证码 换一张
取 消