Khi tôi chuyển một dấu phẩy phức tạp (complex.h) từ trình gọi C++ sang thư viện ac, giá trị không vượt qua chính xác khi chạy trên một máy điện 32 bit. Tôi đã sử dụng hai thư viện phần mềm mã nguồn mở khác nhau khi phát hiện vấn đề này. Tôi đã cô lập nó xuống đến boundry của khi C + + là đi qua một loại giá trị phức tạp đến một chức năng loại C tinh khiết. Tôi đã viết một số mã đơn giản để chứng minh nó.Số phức được chuyển bởi giá trị từ C++ tới C dường như không hoạt động trên 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 */
Các tập tin nguồn C như sau chương trình
#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);
}
Việc kêu gọi C++ như sau
#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;
}
Thông thường tôi mong chờ đầu ra được
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
Nhưng khi tôi chạy nguồn trên n máy điện nhúng pc Tôi nhận được đầu ra cho thấy rằng loại giá trị cho phức tạp không được truyền đúng cách.
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
Tôi đã kiểm tra sizeof paramaters từ gdb và từ cả sự kêu gọi và khung chức năng kích thước là 4 byte, 4 byte, 8 byte và 4 byte, cho float, con trỏ float phức tạp, float phức tạp, và nổi.
Tôi nhận ra mình có thể thay đổi tham số giá trị phức tạp thành con trỏ, hoặc cấu trúc của riêng tôi khi chuyển C++ thành c boundry, nhưng tôi muốn biết tại sao tôi không thể chuyển kiểu phức tạp từ C++ sang c một máy tính điện.
Tôi đã tạo một ví dụ khác chỉ trong lần này tôi đã bán một số bản lắp ráp cũng như các giá trị đăng ký.
int x = 22;
std::complex<float> y = 55 + 88I;
int z = 77;
void simpleProc(int x, complex float y, int z)
Ngay trước khi cuộc gọi nơi các thông số được truyền vào.
x = 22
y = {_M_value = 55 + 88 * I}
Looking at raw data *(int*)&y = 1113325568
z = 77
này mã lắp ráp nên nơi nó tiết kiệm địa chỉ sự trở lại và tiết kiệm thì các tham số để vượt qua thành thói quen.
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>
Nhìn vào lắp ráp ngay sau khi chi nhánh :)
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
Đây là những giá trị khi chúng tôi là hoàn toàn trong các thói quen (sau khi giá trị biến được giao.
x = 22
y = 1.07899982e-43 + 0 * I
z = 265134296
$r3 = 22
$r4 = 0x9ffff938
*(int*)$r4 = 1113325568
$r5 = 77
*(int*)(&y) = 77
My laymans xem là nó trông giống như C + + là đi qua các loại giá trị phức tạp như là một tài liệu tham khảo hoặc loại con trỏ ?, C là xử lý nó như một loại giá trị? Vì vậy, đây là một vấn đề với gcc trên pc điện? Tôi đang sử dụng gcc4.7.1. Tôi a m trong quá trình xây dựng gcc4.9.3 như một trình biên dịch chéo trên một máy khác. Tôi sẽ cập nhật bài đăng này một trong hai cách một khi tôi nhận được đầu ra từ một trình biên dịch mới hơn làm việc.
Có vấn đề với trình biên dịch chéo hoạt động, nhưng nhìn vào kết xuất bộ nhớ của vấn đề ban đầu, nó cho thấy rằng trên nền tảng máy tính điện, giá trị phức tạp không được truyền theo giá trị. Tôi đặt ví dụ về cấu trúc ở đây để cho thấy rằng một giá trị 64 bit có thể được truyền qua giá trị, trên một máy 32 bit.
Đây không phải là vấn đề, nhưng tên bắt đầu bằng dấu gạch dưới theo sau là chữ cái viết hoa ('_MYLIB_H_') và tên có chứa hai dấu gạch dưới liên tiếp được dành riêng cho việc triển khai. Không sử dụng chúng. –
@PeteBecker: Vâng, nó có thể được, ít nhất là trong C nó có thể gọi UB bằng cách thay đổi hành vi của stdlib. – Olaf
Bạn có thể xác minh ABIs (không chắc) và kiểm tra mã Assembler để nhận gợi ý. Nói chung, bạn nên sử dụng các loại tiêu chuẩn. – Olaf