通过引用(在C中)将参数传递给另一个函数是否安全?
以下代码是否安全且可移植通过引用(在C中)将参数传递给另一个函数是否安全?,c,C,以下代码是否安全且可移植 void funcB(int *pA) { // Do something w/ pA } void funcA(int a) { funcB(&a); // Do something else w/ a } 我的理解是,在许多系统上,函数参数被放在CPU寄存器中,而不是堆栈中。因此,实际上是将寄存器的地址传递给函数,然后将其内容推送到堆栈中,这样寄存器就可以用于funcB的参数。因此,实际上,当您在funcB中取消引用pA时,您将从
void funcB(int *pA)
{
// Do something w/ pA
}
void funcA(int a)
{
funcB(&a);
// Do something else w/ a
}
我的理解是,在许多系统上,函数参数被放在CPU寄存器中,而不是堆栈中。因此,实际上是将寄存器的地址传递给函数,然后将其内容推送到堆栈中,这样寄存器就可以用于
funcB
的参数。因此,实际上,当您在funcB
中取消引用pA
时,您将从funcA
获取地址pA
,而不是a
的内容。我的推理是正确的还是完全不正确?编译器将为您处理寄存器分配,并确保&a
是a
中数据的地址,而不是一些随机数据。此外,“寄存器的地址”没有多大意义,因为寄存器没有地址。事实上,表达式&a
会告诉编译器您希望a
是有地址的东西,因此它会将a
中的数据放入内存,然后获取该数据的地址
一个例子
这就是:
它应该是安全的,除非您使用的是一个损坏的编译器。编译器将在堆栈上分配一些区域(通常)并传递其地址,因为需要一个地址 下面是一个关于编译器资源管理器的示例。 我添加了一个函数来“做点什么”,以防止事情被优化
void do_something(int*);
void funcB(int *pA)
{
// Do something w/ pA
do_something(pA);
}
void funcA(int a)
{
funcB(&a);
// Do something else w/ a
}
这是:
这是:
现在您可以看到
funcA
(%edi
)的参数存储在堆栈上,在这两种情况下,它的地址都传递给funcB
。是的,完全安全,并且根据C标准定义良好。函数参数是一个对象,并且(概念上)它有一个地址。funcB
通过指针访问该对象是安全的。请记住,与funcA
中的任何其他局部变量一样,其生存期在funcA
返回时结束,因此funcB
应小心存储指针pA
,以备日后使用
在后台,即使将a
传递给寄存器中的funcA
,如果需要其地址,编译器也需要将该寄存器复制到堆栈上(称为“溢出”),传递该堆栈位置的地址,并使用该地址中的值对a
进行进一步操作。(或者,生成行为“好像”已完成的代码。)
非优化编译器通常会将参数溢出到堆栈中,这样无论是否需要,它都会真正拥有一个地址。但是,如果不需要地址,优化器可以将其去掉,并将参数保留在其寄存器中。您考虑的是什么系统?您是如何编译代码的?这些都是实现定义的,不需要担心。它将不同于平台。而且你的代码是合法的,所以没什么好担心的。在C++ java java登记程序中,只登记了指针,与指针有指针的C++相反,只有引用的Java(Java中的所有对象都是通过引用)。:这取决于实现。我相信有些计算机有内存映射寄存器。@EricPostphil,是的,我认为即使在x86中也有内存映射的隐藏寄存器,但我说的是,有点“常规”寄存器,比如在x86和ARM中,Atmel AVR有“常规”寄存器(R0-R31)这也是映射到32个最低地址的内存。
void do_something(int*);
void funcB(int *pA)
{
// Do something w/ pA
do_something(pA);
}
void funcA(int a)
{
funcB(&a);
// Do something else w/ a
}
funcB:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call do_something
nop
leave
ret
funcA:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
movl %edi, -4(%rbp)
leaq -4(%rbp), %rax
movq %rax, %rdi
call funcB
nop
leave
ret
funcB:
jmp do_something
funcA:
subq $24, %rsp
movl %edi, 12(%rsp)
leaq 12(%rsp), %rdi
call do_something
addq $24, %rsp
ret