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.
精彩评论