这个问题是由于一些混合语言编程而产生的。 我有一个我想用C ++代码调用的Fortran例程。 Fortran通过引用传递其所有参数(除非您另有说明)。

所以我认为在我的C ++代码中我会聪明(糟糕的开始)并定义类似这样的Fortran例程:

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

这段代码工作了一段时间,但(当然,当我需要离开时)突然开始吹回电话。 清除指示一个munged调用堆栈。

一位工程师来到我身后,解决了这一问题,宣布该程序必须在C定义++作为

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

除了两件事,我接受了。 一个是编译器不通过引用传递引用参数似乎相当直观,而且我无法在任何地方找到这样的文档。 另一个是他同时在那里改变了大量其他代码,所以理论上它可能是另一个修改问题的修改。

所以问题是,C ++如何实际传递参考参数? 是否可以免费为小值或其他东西进行复制,复制? 换句话说,参考参数在混合语言编程中是完全无用的吗? 我想知道所以我再也没有犯同样的代码杀戮错误。

#1楼 票数:9

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

也就是说,引用是用指针实现的。 这导致了很多混乱(“引用只是指针”,“引用只是指出了普通部分的指针”)但事实并非如此。 引用是别名,并且始终是别名。

编译器将传递变量的地址,并使用该指针进行操作。 这具有相同的效果(但不一样的语义!)。 更具体地说,编译器可以“替换”这个:

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...
}

为了安全起见。

#2楼 票数:4 已采纳

只是为了插话,我相信你是对的。 我使用引用将参数传递给Fortran函数。 根据我的经验,在Fortran-C ++接口上使用引用或指针是等效的。 我尝试过使用GCC / Gfortran和Visual Studio / Intel Visual Fortran。 它可能依赖于编译器,但我认为基本上所有编译器都通过指针传递实现引用。

#3楼 票数:2

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

这是一个小应用程序:

void foo( int & value )
{
    value = 3;
}


void bar( int *value )
{
    *value = 3;
}

void do_test()
{
    int i;
    foo(i);
    bar(&i);
}

让我们组装它并查看gcc生成的汇编(gcc -s):

        .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 - 拯救Unico给出了C声明可能是问题。 似乎问题是C和fortran之间的互操作性(至少是你正在使用的那两个编译器)。

#4楼 票数:1

没有不同。

unsigned&flag

就像你写的那样

unsigned * const标志

除了操作员访问对象成员(分别为“。”和“ - >”)。

  ask by T.E.D. translate from so

未解决问题?本站智能推荐:

2回复

C++编译器实际上如何在引用参数中传递文字常量?

据我了解(请参阅本文 ),C ++引用实现是基于指针的。 但是,我不知道当没有传递实际变量而是传递文字常量时该机制如何工作。 让我用一个例子来说明我的意思: 我传递给f()函数的是字面量42 。 调用方未使用任何实际变量。 在这种情况下,也许使用了“影子”动态变量和关联的指针?
3回复

C++:编译器能否优化价值传递?

一种通常已知的编译器优化是所谓的返回值优化。 此优化基本上允许编译器不复制从函数返回的局部变量,而是复制它。 但是,我想知道如果已知函数的返回值将覆盖原始参数,是否也可以通过值将参数传递给函数。 这是一个例子。 我们假设我们有以下功能: 然后以下列方式使用此函数: 现在,在这
2回复

C++编译器,通过引用强制传递

是否可以将C ++编译器设置为默认值,以将所有传递的参数解释为按引用定义新的修饰符,以指定您需要通过副本进行传递。 编程我发现,仅依靠我就需要通过拷贝传递数据,因此,至少对我而言,拥有“默认引用”会更有效
3回复

是否有C++编译器选项允许积极删除所有函数调用并将参数传递给具有空主体的函数?

我希望编译器识别出 print 是一个空函数,从而完全删除语句的打印调用和参数评估: 但是,无论我使用哪种优化设置(使用 MSVC),它都将始终执行昂贵函数的计算。 我认识到删除对 ExpensiveFunction 调用的优化可能是一种破坏性优化,但我觉得这应该是可能的,而无需将 print 转
3回复

即使在VisualC++编译器中,在模板中传递“constchar”参数也有些麻烦

大家好,新年快乐! 我在传递模板中的“ const char”参数时遇到了一些麻烦,即使在上一版Visual C ++编译器2013年11月CTP中! 这是简单的代码,在最新的Visual C ++编译器中不起作用,但可以,对于带有选项“ std = c ++ x0”的“ g ++”,是的
4回复

C,编译器错误和指针

我在处理浮点数数组时遇到一些麻烦。 我将一些浮点数组放入ActivationFunc中,然后从那里将相同的数组放入sgnFunction中,由于某种原因,它们最终具有不同的值。 如果从“ sgnFunction(&x,&w);”中删除“&”,则会出现以下编译器错误: 我不明白修复它意味
3回复

从编译器的角度来看,通过const值或constref传递的区别

在c ++的上下文中。 我不知道这之间有什么区别: 和这个: 我确实知道一个值传递,但是从编译器的角度来看,这是一个不会改变的值,所以我的问题是: 在传递const value参数的情况下,仍然需要编译器进行复制吗? 哪一个对编译器的优化程序更好,为什么?
1回复

数据不匹配,编译器无法推断出模板参数

我有这个模板功能最大 我想替换这些: 我需要a和b具有相同的类型。 但是我的代码(从C移植到C ++)具有以下内容: VS2015输出: 好的,我应该将5为size_t 。 我的问题如下:为什么C允许这样做? 更重要的是,引擎盖下会发生什么? 编译器是否将5转换为si