2012-07-14 44 views
0

在下面给出的程序中,两个进程的虚拟地址是相同的。我了解全局变量的原因,但对局部变量无法理解。C和linux中的虚拟地址分配

虚拟地址在运行前如何分配到局部变量?

int main() 
{ 
    int a; 
    if (fork() == 0) 
    { 
    a = a + 5; 
    printf(“%d,%d\n”, a, &a); 
    } 
    else 
    { 
    a = a –5; 
    printf(“%d, %d\n”, a, &a); 
    } 
} 
+0

http://en.wikipedia.org/wiki/Call_stack – 2012-07-14 10:05:50

+2

顺便提一下,使用'%p'而不是'%d'指针。 – 2012-07-14 10:06:15

回答

2

编译时,编译器决定使用堆栈或寄存器作为局部变量。在这种情况下,堆栈。

它还决定放置堆栈的(虚拟)地址空间中的哪个位置。

因此,对于这两个进程,堆栈以相同(虚拟)地址开始。而且由于这个特定程序的流程是相当确定性的,两个进程的堆栈帧看起来完全相同,导致堆栈中'a'的偏移量相同。

+0

它比这更简单'a'开始* 'fork',所以它不仅是实现细节的结果,而且实际上是* required,所以'a'在两个地址中都有相同的地址。实际上,我想知道这是否是某些优化编译器在某些情况下可能出错的原因当变量“应该有”存在于“fork”之前时,执行“懒惰”的堆栈变量分配(也许在分配VLA后,在子和父级中具有不同的大小),因此在父子代中必须具有相同的地址... – 2012-07-14 12:12:11

3

虚拟地址是......虚拟的。这意味着来自两个不同进程(如父进程及其子进程)的相同虚拟地址指向两个不同的物理地址。

+0

但是当一个程序被编译时如何以及为什么虚拟地址被赋予局部变量?只有当函数调用正确时才需要它们? – Dhatri 2012-07-14 10:13:33

+0

局部变量存储在堆栈中,不再需要时将其删除 – 2012-07-14 10:19:00

+0

局部变量仅在运行时获取地址;编译器不给它们一个“地址”,而是一个相对于堆栈指针的“偏移量”(比如'这个变量是离堆栈顶部16个字节')。在你的情况下,堆栈指针将是在fork()之后的两个进程中都是一样的,所以在两个进程中应用相同的偏移量之后,仍然会得到相同的地址 – 2012-07-14 10:20:15

0

无论a在分叉前的地址是什么,在分叉之后肯定是一样的,所以它在两个进程中必然是相同的,因为它们的地址为a都等于相同的东西。在大多数实现中,a的地址是通过将偏移量(由编译器确定)添加到堆栈指针的内容而得出的。叉指针的内容被重复。