0

这是我的测验问题(警告,冗长):

给定以下程序,重新排序 printf 行,以便如果在 Sun SPARC 体系结构上编译和运行,打印的值从小到大排序。这些行使用 printf() 格式说明符 %p (指针)打印出程序不同部分的十六进制地址(不是分配的值)。

#include <stdio.h> 
#include <stdlib.h> 
int a = 420; 
void foo() { 
    int b; 
    /* 1 */ printf( "b --> %p\n", &b ); 
} 

int 
    main( int argc, char *argv[] ) { 
        int c; 
        int d = 42; 
        static int e; 
        /* 2 */ (void) printf( "foo() --> %p\n", foo ); 
        /* 3 */ (void) printf( "e --> %p\n", &e ); 
        /* 4 */ (void) printf( "malloc --> %p\n", malloc(420) ); 
        foo(); 
        /* 5 */ (void) printf( "d --> %p\n", &d ); 
        /* 6 */ (void) printf( "argv --> %p\n", &argv ); 
        /* 7 */ (void) printf( "a --> %p\n", &a ); 
        /* 8 */ (void) printf( "c --> %p\n", &c ); 
        /* 9 */ (void) printf( "argc --> %p\n", &argc ); 
    return 0; 
} 

我在 C 中运行了这个程序并得到了这些打印值:

2  foo() --> 10594
3  e --> 2099c
4  malloc --> 209a8
1  b --> ffbff1b4
5  d --> ffbff228
6  argv --> ffbff288
7  a --> 20974
8  c --> ffbff22c
9  argc --> ffbff284

我的问题很好……为什么?我尝试手动执行此操作,记住每个变量的保存位置(堆栈、BSS、数据等),并尝试命令他们说这是变量的顺序,从低内存到高内存:

这是从最小到最小的组织方式吗?

LOW MEMORY - text (labels, function names):
2 - foo
data (initialized global/static vars):
7 - a
BSS ( initialized global/static vars:
3 - e
stack (local vars):
9 - argc
6 - argv[]
8 - c
5 - d
1 - b
4 - ptr returned by malloc
HIGH MEMORY

如果它与打印的内存值冲突,我不知道为什么,有人介意解释为什么吗?谢谢 :) !

4

1 回答 1

2

唯一的冲突是在堆栈区。

如果堆栈从较高地址增长到较低地址(这是通常的情况)或其他方式,这取决于系统。

在堆栈的底部有argcand argv,然后是cand ,d然后是b

由于参数以“错误的方式”被推入堆栈,首先argv被推入,然后argc,给出argc一个较小的地址。c显然,和也是d如此;但我认为编译器可以自由选择放置局部变量的位置。

b具有最小的地址,因为它被推送得很晚。

此外,返回的 ptrmalloc()不是在堆栈上,而是在堆上,堆在BSS区域之后立即开始。

这使得解决方案

LOW MEMORY
text (labels, function names):
2 - foo
data (initialized global/static vars):
7 - a
BSS (initialized global/static vars):
3 - e
heap:
4 - ptr returned by malloc
stack (local vars):
1 - b
5 - d
8 - c
9 - argc
6 - argv[]
HIGH MEMORY

这种不直观的参数传递顺序的原因是因为有可变 llength 参数的选项。你可能知道 function printf(),所有这些调用都是有效的:

printf("Hello\n");
printf("Hello %s\n", name);
printf("Hello User #%d (%s)\n", nr, name);

只有调用者知道变量的数量。被调用的函数知道堆栈的顶部,并希望对第一个参数有一个定义的偏移量。所以唯一的选择是将第一个参数放在堆栈的顶部,从而开始从最后一个推到第一个。通常,实际上并没有推送数据,而是手动减少堆栈指针,然后以这种方式保留的内存被填充。

于 2011-12-01T08:50:03.667 回答