代码之家  ›  专栏  ›  技术社区  ›  T.E.D.

C++编译器如何传递引用参数?

  •  15
  • T.E.D.  · 技术社区  · 15 年前

    这个问题是混合语言编程的结果。我有一个FORTRAN程序,我想用C++代码调用。Fortran通过引用传递它的所有参数(除非你告诉它)。

    extern "C" void FORTRAN_ROUTINE (unsigned & flag);
    

    extern "C" void FORTRAN_ROUTINE (unsigned * flag);
    

    我会接受的,除了两件事。其一,编译器不通过似乎有点违反直觉 参考参数

    所以问题是,C++如何真正传递引用参数?它是否可以自由地进行拷贝输入、拷贝输出以获得较小的值或其他什么?换句话说,在混合语言编程中,引用参数是完全无用的吗?我想知道,这样我就不会再犯同样的杀码错误了。

    4 回复  |  直到 15 年前
        1
  •  4
  •   Victor Liu    15 年前

    顺便说一句,我相信你是对的。我一直使用引用将参数传递给Fortran函数。在我的经验中,使用FordRAN-C++接口中的引用或指针是等价的。我已经用GCC/Gfortran和visualstudio/Intel-visualfortran试过了。它可能依赖于编译器,但我认为基本上所有编译器都通过指针传递来实现引用。

        2
  •  9
  •   GManNickG    15 年前

    C++没有定义实现应该如何,它只是一种语言。所以没有引用的“a”实现。

    这个案子。引用是别名,并且始终是别名。

    void make_five(int& i)
    {
        i = 5;
    }
    
    int main(void)
    {
        int i = 0;
        make_five(i);
    }
    

    有了这个:

    void make_five(int* const i)
    {
        *i = 5;
    }
    
    int main(void)
    {
        int i = 0;
        make_five(&i);
    }
    

    请记住推荐人是首选。这就是引用和指针之间的区别很重要的地方。是要给变量加别名,还是指向它?大多数时候,前者。在C语言中,必须使用指针来实现这一点,这导致了C程序员普遍的误解,即引用实际上是指针。

    要获得类似的语义(因为您现在指向的是一个变量,而不是它的别名),您应该确保指针的值不为null:

    extern "C" void FORTRAN_ROUTINE (unsigned * flag)
    {
        assert(flag); // this is normally not a problem with references, 
                      // since the address of a variable cannot be null.
    
        // continue...
    }
    

    只是为了安全。

        3
  •  2
  •   elcuco    15 年前

    从理论上讲,C++中的引用是作为普通指针实现的。编译器然后像引用一样更改函数tonehave的代码,但是加载地址,然后间接移动地址。

    下面是一个小应用程序:

    void foo( int & value )
    {
        value = 3;
    }
    
    
    void bar( int *value )
    {
        *value = 3;
    }
    
    void do_test()
    {
        int i;
        foo(i);
        bar(&i);
    }
    

            .file   "test-params.cpp"
            .text
    .globl _Z3fooRi
            .type   _Z3fooRi, @function
    _Z3fooRi:
    .LFB0:
            .cfi_startproc
            .cfi_personality 0x0,__gxx_personality_v0
            pushl   %ebp
            .cfi_def_cfa_offset 8
            movl    %esp, %ebp
            .cfi_offset 5, -8
            .cfi_def_cfa_register 5
            movl    8(%ebp), %eax
            movl    $3, (%eax)
            popl    %ebp
            ret
            .cfi_endproc
    .LFE0:
            .size   _Z3fooRi, .-_Z3fooRi
    .globl _Z3barPi
            .type   _Z3barPi, @function
    _Z3barPi:
    .LFB1:
            .cfi_startproc
            .cfi_personality 0x0,__gxx_personality_v0
            pushl   %ebp
            .cfi_def_cfa_offset 8
            movl    %esp, %ebp
            .cfi_offset 5, -8
            .cfi_def_cfa_register 5
            movl    8(%ebp), %eax
            movl    $3, (%eax)
            popl    %ebp
            ret
            .cfi_endproc
    .LFE1:
            .size   _Z3barPi, .-_Z3barPi
    .globl _Z7do_testv
            .type   _Z7do_testv, @function
    _Z7do_testv:
    .LFB2:
            .cfi_startproc
            .cfi_personality 0x0,__gxx_personality_v0
            pushl   %ebp
            .cfi_def_cfa_offset 8
            movl    %esp, %ebp
            .cfi_offset 5, -8
            .cfi_def_cfa_register 5
            subl    $20, %esp
            leal    -4(%ebp), %eax
            movl    %eax, (%esp)
            call    _Z3fooRi
            leal    -4(%ebp), %eax
            movl    %eax, (%esp)
            call    _Z3barPi
            leave
            ret
            .cfi_endproc
    .LFE2:
            .size   _Z7do_testv, .-_Z7do_testv
            .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
            .section        .note.GNU-stack,"",@progbits
    

    如您所见,在这两个函数中,编译器都读取( stack movl 8(%ebp), %eax ),在这两个调用中,编译器都将地址保存到堆栈中( leal -4(%ebp), %eax)

    GMan-Save联通给出的关于C声明的答案可能就是问题所在。问题似乎是C和fortran之间的互操作性(至少是您正在使用的那两个编译器)。

        4
  •  1
  •   Poni    15 年前

    未签名(&A);旗帜

    和你写的一模一样

    无符号*常量标志