Lorsque je passe un flottant complexe (complex.h) d'un appelant C++ vers une bibliothèque ac, la valeur ne passe pas correctement lors de l'exécution un PC de puissance de 32 bits. J'utilisais deux bibliothèques logicielles open source différentes lorsque j'ai détecté ce problème. Je l'ai isolé à la limite de quand C++ passe un type de valeur complexe à une fonction de type C pure. J'ai écrit un code simple pour le démontrer.Les nombres complexes passés de C++ à C ne semblent pas fonctionner sur powerpc
#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 */
Le fichier source C est comme suit
#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);
}
Le programme appelant C++ est comme suit
#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;
}
Normalement, j'attendre que la sortie soit
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
Mais quand je cours la source sur un n La machine de puissance embarquée de puissance Je reçois la production qui montre que le type de valeur pour le complexe n'est pas passé correctement.
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
J'ai vérifié les sizeof les paramaters de gdb et à la fois l'appel et le cadre de fonction, les tailles sont 4 octets, 4 octets, 8 octets et 4 octets, pour le flotteur, le pointeur de flotteur complexe, flotteur complexe, et flotter. Je réalise que je peux simplement changer le paramètre de valeur complexe en tant que pointeur, ou ma propre structure lorsque je croise la limite de C++ en c, mais je veux savoir pourquoi je ne peux pas passer un type de valeur complexe de C++ à c un pc de puissance.
J'ai créé un autre exemple seulement cette fois que j'ai jeté une partie de l'ensemble ainsi que les valeurs de registre.
int x = 22;
std::complex<float> y = 55 + 88I;
int z = 77;
void simpleProc(int x, complex float y, int z)
Juste avant appel où les paramètres sont passés dans.
x = 22
y = {_M_value = 55 + 88 * I}
Looking at raw data *(int*)&y = 1113325568
z = 77
Ce devrait être le code assembleur où il enregistre le l'adresse de retour et enregistre les paramters à passer dans la routine.
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>
En regardant l'assemblée juste après la branche :)
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
Ce sont la valeur une fois que nous sommes tout à fait dans la routine (après les valeurs des variables sont affectées.
x = 22
y = 1.07899982e-43 + 0 * I
z = 265134296
$r3 = 22
$r4 = 0x9ffff938
*(int*)$r4 = 1113325568
$r5 = 77
*(int*)(&y) = 77
Mon la vue des profanes est qu'il semble que le C++ passe le type de valeur complexe comme référence ou type de pointeur? mais C le traite comme un type de valeur? Donc, est-ce un problème avec gcc sur le pc de puissance? J'utilise gcc4.7.1. Je suis un m en train de construire gcc4.9.3 en tant que compilateur croisé sur une autre machine. Je mettrai à jour ce post de toute façon une fois que je recevrai la sortie d'un compilateur plus récent. Si vous rencontrez des problèmes pour faire fonctionner le compilateur croisé, mais en regardant l'image mémoire du problème d'origine, cela montre que sur la plate-forme du PowerPC, la valeur complexe n'est pas transmise par valeur. J'ai mis l'exemple de la structure ici pour montrer qu'une valeur de 64 bits peut être transmise par valeur, sur une machine 32 bits.
Ce n'est pas le problème, mais les noms qui commencent par un trait de soulignement suivi d'une lettre majuscule ('_MYLIB_H_') et les noms qui contiennent deux traits de soulignement consécutifs sont réservés à l'implémentation. Ne les utilisez pas. –
@PeteBecker: Eh bien, il peut être, au moins en C, il pourrait invoquer UB en changeant le comportement de stdlib. – Olaf
Vous pouvez vérifier les ABI (improbables) et vérifier le code de l'assembleur pour obtenir un indice. En général, vous devez utiliser les types standard. – Olaf