Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过引用(在C中)将参数传递给另一个函数是否安全?_C - Fatal编程技术网

通过引用(在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