我无法理解MS VC编译器在此问题上的行为。这行很好,但我得到的结果并不是我所期望的:
this->Test((char *)&CS2 - (char *)&CS1 == sizeof(void *));
CS1和CS2参数声明如下:
myFunction(tCS1* CS1, tCS2* CS2) {...
tCS1和tCS2是包含一个int和一个__int64的结构,分别为
这是为了检查我的参数CS1和CS2之间的堆栈距离,它们都是指针。当我在这一行中断执行并使用调试器获取我的两个变量的地址时,我发现它们确实相距8个字节(x64平台)。
然而,比较的结果是错误的。
以下是编译器生成的汇编代码:
mov rax,qword ptr [CS1]
mov rdi,qword ptr [CS2]
sub rdi,rax
(然后它使用存储在rdi中的结果进行比较,并进行调用)
是的,编译器正在比较我的指针参数的值,而不是它们的地址。我在这里错过了间接水平,它去了哪里?
当然我无法在测试环境中重现这一点,而且我也不知道在哪里可以查看。 我在32位机器上将这段代码交叉编译到x64平台(我必须),这是关于它的唯一“奇怪”事情。任何想法,任何提示?
答案 0 :(得分:0)
集会
mov rax,qword ptr [CS1]
mov rdi,qword ptr [CS2]
sub rdi,rax
表示CS1和CS2不是真正的堆栈参数,而是一些全局符号 - 如果我想产生类似的结果,我会做这样的事情:
int* CS1 = NULL, *CS2 = NULL; /* or any other value...*/
#define CS1 *CS1
#define CS2 *CS2
当然这是丑陋的代码 - 但你检查过你的代码中没有这些东西吗?此外,动态链接器可能会在其中发挥作用。
最后但并非最不重要:如果您尝试编写如下代码:
void foo()
{
int a;
int b;
printf("%d", &a-&b);
}
你应该知道这实际上是未定义的行为,因为C(和C ++)只允许减去指向单个对象(例如数组)内部的指针。
答案 1 :(得分:0)
正如@jpalacek和评论者观察到的那样,这是未定义的,编译器可能会利用它来做任何喜欢的事情。这很奇怪。
此代码“适用于”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.
并且通过优化它只知道它们的相对地址:
(编辑:答案因某种原因被截断)
(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.
有趣的是,通过-O4
优化,它返回+4而没有它,它返回-4。
你为什么要这样做呢?通常不能保证参数有任何内存地址:它们可以在寄存器中传递。