繁体   English   中英

C中的激活记录

[英]Activation Record in 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个单位。

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

GCC sayeth(无可鼓励错误报告的参数):

$ 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
$

zc中的代码是问题中的代码,其前面带有' #include <stdio.h> '和空白行。

GCC在说真话-代码在C上破烂-沉迷于未定义的行为(将整数5转换为整数指针,而无需强制转换以告知编译器程序员可以做什么)。

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

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

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

当您在main()中调用'test(5,10)'时,文字'5'不会在test()函数内部解释为整数,而是作为指针(因此,编译器感到悲伤:“使用整数创建指针而没有演员”)。

您不是在传递数组作为值,而是在传递int,0x0000005或其他任何值。

您要传递两个刚刚分配的变量,即在堆栈上。 因此,您已为两个整数(每个4字节)分配了空间。 因此,当您找到他们的地址时,它们应该分开4个。

欢迎来到代码不是类型安全内存也不安全的世界


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

我记得,您无法通过MS C ++获得这样的程序,因此我认为您正在使用gnu。 在这种情况下,我会建议-Wall -Werror

正如其他人指出的那样,您正在传递一个文字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]);

您需要先执行此操作,然后才能致电告知显示的地址是否看起来“奇怪”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM