C中的激活记录

时间:2009-09-26 06:04:38

标签: c

void test(int p1[10], int p2) {
    int l1;
    int l2[10];

    printf("params are at %d and %d\n", &p1, &p2);
    printf("locals are at %d and %d\n", &l1, &l2[0]);
}


int main(void) {
    test(5, 10);
}

我对上面的代码感到有点困惑...当函数已经指定了p [10]的数组时,我们如何为测试函数提供5的参数。输出地址也很奇怪,p1和p2应该相隔40个地址(10个元素的数组乘以每个int 4个字节)。但是控制台显示它们只有4个单位......

6 个答案:

答案 0 :(得分:4)

  1. 5被隐式转换为指向int的指针(即0x00000005)。
  2. 第一个数组参数实际上等同于一个指向int的指针,因为你不能按C中的值传递数组。因此,您将在堆栈上获取两个局部变量的地址(指向int和int)。每个都是4个字节,因此它们的地址之间有4个字节的差异。

答案 1 :(得分:3)

海湾合作委员会说(没有鼓励错误报告的论据):

$ gcc -c z.c
z.c: In function ‘main’:
z.c:13: warning: passing argument 1 of ‘test’ makes pointer from integer
without a cast
$

z.c中的代码是问题中的代码,前面是“#include <stdio.h>”和一个空行。

GCC正在说实话 - 代码在C上破灭 - 沉迷于未定义的行为(将整数5转换为指向整数的指针,没有强制转换告诉编译器程序员有任何线索他们到底是什么)。

因为p1等于'int * p1',所以p1和p2(4)的距离对于32位编译是正确的。

答案 2 :(得分:1)

test()函数有两个参数:指针p1(指向10个整数的数组)和一个整数p2。在堆栈上,p2位于较高地址,p1位于较低地址。 p2和p1的起始地址之间的差异是p2(== 4)的大小。

该函数在堆栈上有两个局部变量:较高地址上的整数l1和较低地址上的数组l2(10个整数)。 l1和l2的起始地址之间的差异是l2数组的大小(== 4 * 10)。

当你在main()中调用'test(5,10)'时,文字'5'将不会在test()函数内部解释为整数但是作为指针(因此编译器悲伤:“使指针来自没有强制转换的整数“)。

答案 3 :(得分:0)

您没有将数组作为值传入,只是传递一个int,0x0000005或其他任何内容。

您正在传递两个刚刚分配的变量,即在堆栈上。所以你已经分配了两个整数的空间,每个4个字节。因此,当你找到他们的地址时,它们应该相隔4个。

答案 4 :(得分:0)

欢迎来到代码不是type-safe而不是memory-safe

的世界

并记住他们对“天使害怕踩踏”的所说的话。 C中的数组参数会自动重写为“指向数组的指针”5的指针肯定是不正确的,但C会用它运行** ... **一段时间。

我记得你无法通过MS C ++获得这样的程序,所以我想你正在使用gnu。在这种情况下,我建议-Wall -Werror

答案 5 :(得分:0)

正如其他人已经注意到你传递了一个文字int(5),它被转换为传递给test函数的指针类型。在函数参数中,所有顶级数组声明都转换为指针,因此可以等效地编写测试

void test( int* p1, int p2 )

您的printf电话存在问题。 %dint的格式说明符,而不是指针类型。要正确地将指针传递给printf,您应该明确地转换为void*并使用%p格式说明符。

printf("params are at %p and %p\n", (void*)&p1, (void*)&p2);
printf("locals are at %p and %p\n", (void*)&l1, (void*)&l2[0]);

在打电话询问显示的地址是否“奇怪”之前,您需要这样做。