2013-10-15 154 views
0

为什么下面的代码打印0?即为什么变量a位于变量d之后,即使指针变量c正在它们之间声明?为什么这段代码打印0

#include<iostream> 
using namespace std; 

int main() { 
    unsigned int a = 100; 
    unsigned int &b = a; 
    unsigned int *c = &b; 
    unsigned int d = (unsigned int)(c); 
    int e = &d - c; 
    int &f = e; 
    e ++; 
    cout << e << " " << endl; 
    return 0; 
} 
+14

减去指向不相关的对象是不确定的行为。编译器可以生成任何喜欢的代码。它确实如此。 – rici

+2

它为我打印2。 – deepmax

+0

而这并不打印0,对我来说它打印2? – Annabelle

回答

2

工作向后:

e ++; 
cout << e << " " << endl; 

如果打印0,那么e这段代码执行前的值一定是-1

int e = &d - c; 

所以上述地址相减的结果一定是-1

unsigned int a /* = whatever, the value of a doesn't matter */; 
unsigned int &b = a; 
unsigned int *c = &b; 
unsigned int d /* = whatever, the value of d doesn't matter */; 

ba的引用,所以&b相当于&a

所以&d - c相当于&d - &a,那减法得到-1

结论:d地址为的a地址后sizeof (unsigned int)字节。 (指针减法按指定类型的大小缩放。)

可能。

实际上,减去指向两个独立定义对象的指针的行为是undefined。该标准完全没有说明它应该做什么。

在实践中,编译器可能会产生一个指针减法尽可能简单的代码,并且简单的代码可能会治疗无关的指针仿佛他们相媲美,即使语言不说他们是。

根据程序的输出结果,很可能bd恰好相互分配。没有说任何声明的变量必须按照你声明的顺序进行分配。如果希望对象按定义顺序分配到内存中,请将它们放入struct或将它们设置为数组的元素。

如果您在不同的系统上运行它,或者在具有不同编译器的同一系统上运行它,或者在具有不同编译器选项的相同编译器的同一系统上运行它,也可能会产生不同的结果。原则上,它甚至可以在一切相同但在月球的不同阶段表现不同。

而编译器被允许为假设您的代码的行为已被很好地定义,并执行仅在给定假设的情况下有效的转换。实际上,通过减去两个不相关的指针,你已经答应编译器它们都指向同一个数组对象的元素或刚刚超过它的末尾(其中一个对象被视为1个元素的数组)是空指针;这是C和C++之间的区别)。你已经对编译器撒谎了,这意味着它对你没有进一步的义务。

不要这样做。

+1

'b'实际上是一个绑定到'a'的引用,所以“向后工作”过程在技术上应该包含一个额外的步骤:'&b'实际上是'&a',这意味着'&d -c'等价于'&d - &a'。但OP显然已经知道,因为这正是问题中所说的。 – AnT

+0

@AndreyT:啊,我错过了参考。固定。 –

0

除非你明确地使用自己的内存管理系统将物体,它们在内存中的相对位置将是反编译和系统的依赖性。

-1

您的线路int e = &d - c;正在减速2 unsigned int *

在内存中,&d是8字节,然后是c(它取决于您的系统,但我们假设int是4字节)。实际上,你建立你的筹码以这样的方式

unsigned int a = 100;    // &a is 0x0 
unsigned int &b = a;     // &b is 0x0 (it's just an alias) 
unsigned int *c = &b;    // &c is 0x4 
unsigned int d = (unsigned int)(c); // &d is 0x8 

unsigned int使用内存4个字节。因此,当你在做&d - c时,它必须返回2,因为你正在使用指针运算与unsigned int*(4 * 2 = 8);所以,当你在做&d - c时,它必须返回2

您可以尝试使用int e = (short*)&d - (short*)c结果应为4,因为short大小为2(2 * 4 = 8)。

你可以试试int e = (char*)&d - (char*)c结果应该是8,因为char大小是1(1 * 8 = 8)。

尝试打印变量和地址了解:

#include<iostream> 
using namespace std; 

int main() { 
    unsigned int a = 100; 
    unsigned int &b = a; 
    unsigned int *c = &b; 
    unsigned int d = (unsigned int)(c); 
    int e = (short*)&d - (short*)c; 
    //int &f = e;                                         
    //e ++;                                           

    cout << "&a: " << (unsigned int)&a << endl; 
    cout << "&b: " << (unsigned int)&b << endl; 
    cout << "&c: " << (unsigned int)&c << endl; 
    cout << "&d: " << (unsigned int)&d << endl; 

    cout << endl; 

    cout << " a: " << a << endl; 
    cout << " b: " << b << endl; 
    cout << " c: " << (unsigned int)c << endl; 
    cout << " d: " << d << endl; 

    cout << endl; 

    cout << " e: " << e << endl; 
    return 0; 
} 

这里,int e = (short*)&d - (short*)c;,结果是:

&a: 3220197356 
&b: 3220197356 
&c: 3220197360 
&d: 3220197364 

a: 100 
b: 100 
c: 3220197356 
d: 3220197356 

e: 4