从C++到C的值传递的复数似乎不适用于powerpc

dan*_*dan 11 c c++ powerpc pass-by-value complex-numbers

当我将复杂的float(complex.h)从c ++调用者传递到ac库时,在32位power pc上运行时,该值无法正确传递.当我发现这个问题时,我正在使用两个不同的开源软件库.我把它分离到C++将复杂值类型传递给纯C类型函数的边界.我写了一些简单的代码来演示它.

#ifndef MMYLIB_3A8726C1_H
#define MMYLIB_3A8726C1_H

typedef struct aComplexStructure {
    float r;
    float i;
} myComplex_t;

#ifdef __cplusplus
#include <complex>
extern "C" {
    void procWithComplex(float a, std::complex<float> *pb, std::complex<float> c, float d);
    void procWithStruct(float a, myComplex_t *pb, myComplex_t c, float d);
}

#else  /* __cplusplus */

#include <complex.h>
void procWithComplex(float a, float complex *pb, float complex c, float d);
void procWithStruct(float a, myComplex_t *pb, myComplex_t c, float d);

#endif

#endif /* MYLIB_3A8726C1_H */
Run Code Online (Sandbox Code Playgroud)

源C文件如下

#include <stdio.h>
#include "myLib.h"

void procWithComplex(float a, complex float * pb, complex float  c, float d)
{
    printf("a=%f\n", a);
    printf("b=%f + %fi\n", creal(*pb), cimag(*pb));
    printf("c=%f + %fi\n", creal(c), cimag(c));
    printf("d=%f\n", d);
}


void procWithStruct(float a, myComplex_t* pb, myComplex_t c, float d)
{
    printf("a=%f\n", a);
    printf("b=%f + %fi\n", pb->r, pb->i);
    printf("c=%f + %fi\n", c.r, c.i);
    printf("d=%f\n", d);
}
Run Code Online (Sandbox Code Playgroud)

调用C++程序如下

#include <iostream>
#include "myLib.h"

int main()
{
    float a = 1.2;
    std::complex<float> b = 3.4 + 3.4I;
    std::complex<float> c = 5.6 + 5.6I;
    float d = 9.876;

    myComplex_t b_s, c_s;

    b_s.r = b.real();
    b_s.i = b.imag();

    c_s.r = c.real();
    c_s.i = c.imag();

    std::cout << "a=" << a << std::endl;
    std::cout << "b=" << b << std::endl;
    std::cout << "c=" << c << std::endl;
    std::cout << "d=" << d << std::endl << std::endl;

    // c is a 64 bit structure being passed by value.
    // on my 32 bit embedded powerpc platform, it is being
    // passed by reference, but the underlying C library is
    // reading it by value.
    procWithComplex(a, &b, c, d);
    std::cout << std::endl;

    // This is only here to demonstrate that a 64 bit value field
    // does pass through the C++ to C boundry
    procWithStruct(a, &b_s, c_s, d);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

通常我会期望输出

a=1.2
b=(3.4,3.4)
c=(5.6,5.6)
d=9.876

a=1.200000
b=3.400000 + 3.400000i
c=5.600000 + 5.600000i
d=9.876000

a=1.200000
b=3.400000 + 3.400000i
c=5.600000 + 5.600000i
d=9.876000
Run Code Online (Sandbox Code Playgroud)

但是当我在嵌入式power pc机器上运行源代码时,我得到的输出显示复杂的值类型没有正确传递.

a=1.2
b=(3.4,3.4)
c=(5.6,5.6)
d=9.876

a=1.200000
b=3.400000 + 3.400000i
c=-0.000000 + 9.876000i
d=0.000000

a=1.200000
b=3.400000 + 3.400000i
c=5.600000 + 5.600000i
d=9.876000
Run Code Online (Sandbox Code Playgroud)

我从gdb和调用函数框架检查了参数的大小,大小为4字节,4字节,8字节和4字节,用于浮点数,复数浮点指针,复数浮点数和浮点数.

我意识到我可以将复数值参数更改为指针,或者在将c ++交叉到c边界时更改我自己的结构,但我想知道为什么我无法在power pc上将复杂的值类型从c ++传递给c.

我创建了另一个例子,这次我抛弃了一些程序集以及寄存器值.

int x = 22;
std::complex<float> y = 55 + 88I;
int z = 77;
void simpleProc(int x, complex float y, int z)
Run Code Online (Sandbox Code Playgroud)

在调用之前传递参数的位置.

x = 22
y =  {_M_value = 55 + 88 * I} 
Looking at raw data *(int*)&y = 1113325568
z = 77
Run Code Online (Sandbox Code Playgroud)

这应该是汇编代码,它保存返回地址并保存参数以传递给例程.

x0x10000b78 <main()+824> lwz     r9,40(r31)
x0x10000b7c <main()+828> stw     r9,72(r31)
x0x10000b80 <main()+832> lwz     r9,44(r31)
x0x10000b84 <main()+836> stw     r9,76(r31)   
x0x10000b88 <main()+840> addi    r9,r31,72    
x0x10000b8c <main()+844> lwz     r3,16(r31)   
x0x10000b90 <main()+848> mr      r4,r9       
x0x10000b94 <main()+852> lwz     r5,20(r31)   
x0x10000b98 <main()+856> bl      0x10000f88 <simpleProc>  
Run Code Online (Sandbox Code Playgroud)

看看分支后的组装:)

x0x10000f88 <simpleProc>         stwu    r1,-48(r1)  
x0x10000f8c <simpleProc+4>       mflr    r0      
x0x10000f90 <simpleProc+8>       stw     r0,52(r1)   
x0x10000f94 <simpleProc+12>      stw     r29,36(r1)  
x0x10000f98 <simpleProc+16>      stw     r30,40(r1)  
x0x10000f9c <simpleProc+20>      stw     r31,44(r1)  
x0x10000fa0 <simpleProc+24>      mr      r31,r1      
x0x10000fa4 <simpleProc+28>      stw     r3,8(r31)  
x0x10000fa8 <simpleProc+32>      stw     r5,12(r31) 
x0x10000fac <simpleProc+36>      stw     r6,16(r31)  
x0x10000fb0 <simpleProc+40>      stw     r7,20(r31)  
x0x10000fb4 <simpleProc+44>      lis     r9,4096  
Run Code Online (Sandbox Code Playgroud)

这些是我们完全在例程中的值(在赋值变量值之后).

x = 22
y =  1.07899982e-43 + 0 * I
z = 265134296

$r3 = 22
$r4 = 0x9ffff938
*(int*)$r4 = 1113325568
$r5 = 77

*(int*)(&y) = 77
Run Code Online (Sandbox Code Playgroud)

我的外行观点是看起来C++将复杂值类型作为引用或指针类型传递?但是C会把它当成一种价值类型吗?那么这是关于power pc上的gcc的问题吗?我正在使用gcc4.7.1.我正在构建gcc4.9.3作为另一台机器上的交叉编译器.一旦我从新编译器的输出中获得输出,我将以任一方式更新此帖子.

在让交叉编译器工作时遇到问题,但是查看原始问题的内存转储,它确实表明在power pc平台上,复杂值没有按值传递.我在这里放置了struct的示例,以显示在32位计算机上可以通过值传递64位值.

M.M*_*M.M 4

您的代码会导致未定义的行为。在 C++ 单元中,函数声明为:

extern "C" void procWithComplex(float a, std::complex<float> *pb, std::complex<float> c, float d);
Run Code Online (Sandbox Code Playgroud)

但函数体是:

void procWithComplex(float a, complex float * pb, complex float  c, float d)
Run Code Online (Sandbox Code Playgroud)

哪个不匹配。

为了帮助编译器诊断此错误,您应该避免使用预处理器为同一函数切换不同的原型。

为了避免此错误,您需要让函数原型仅使用在 C 和 C++ 中都有效的类型。就像您在myComplex_t示例中所做的那样。