2009-11-20 6 views
8

Thông thường tôi làm việc với vectơ 3D sử dụng các loại sau đây:C - Làm thế nào để truy cập vào các yếu tố của vector sử dụng phần mở rộng vector GCC SSE

typedef vec3_t float[3]; 

khởi vectơ sử dụng smth. như:

vec3_t x_basis = {1.0, 0.0, 0.0}; 
vec3_t y_basis = {0.0, 1.0, 0.0}; 
vec3_t z_basis = {0.0, 0.0, 1.0}; 

và truy cập chúng bằng smth. như:

x_basis[X] * y_basis[X] + ... 

Bây giờ tôi cần một véc tơ arithmetics sử dụng hướng dẫn SSE. Tôi có mã sau đây:

typedef float v4sf __attribute__ ((mode(V4SF))) 
int main(void) 
{ 
    v4sf a,b,c; 
    a = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    b = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    c = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    a = b + c; 
    printf("a=%f \n", a); 
    return 0; 
} 

GCC hỗ trợ cách này. Nhưng ... Đầu tiên, nó mang lại cho tôi 0,0000000 kết quả. Thứ hai, tôi không thể truy cập vào các phần tử của các vectơ đó. Câu hỏi của tôi là: làm thế nào tôi có thể truy cập các phần tử của các vectơ như vậy? Tôi cần smth. giống như một [0] để truy cập yếu tố X, a [1] để truy cập yếu tố Y vv

PS: Tôi biên dịch mã này sử dụng:

gcc -msse testgcc.c -o testgcc 
+0

Các câu hỏi không quá khó và tôi không tự coi mình là chuyên gia về gcc. Lần sau sử dụng một tiêu đề vô hại hơn, tôi gần như bỏ qua câu hỏi. – hirschhornsalz

Trả lời

16

Cách an toàn và được khuyến nghị để truy cập các phần tử là với công đoàn, thay vì loại punning, loại bỏ cơ chế phát hiện răng cưa của trình biên dịch và có thể dẫn đến mã không ổn định.

union Vec4 { 
    v4sf v; 
    float e[4]; 
}; 

Vec4 vec; 
vec.v = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
printf("%f %f %f %f\n", vec.e[0], vec.e[1], vec.e[2], vec.e[3]); 

+1

không, elder_george đã đưa ra một ví dụ thực tế hơn - nó đủ an toàn nếu bạn thực hiện lời khuyên của mình trong một macro hoặc trong một nội tuyến – psihodelia

+2

Có vẻ như tôi chưa đủ rõ ràng. Loại punning với con trỏ là xấu bởi vì dereferencing một con trỏ loại-punned sẽ phá vỡ quy tắc bí danh nghiêm ngặt. Điều này dẫn đến hành vi không xác định. Nó không được an toàn hơn bằng cách nội tuyến hoặc macro. Nhưng bạn có thể sử dụng tùy chọn trình biên dịch _-fno-strict-aliasing_, được tạo chính xác cho mã bị hỏng như thế này. Các tập tin nhị phân kết quả có thể hơi chậm hơn, bởi vì bạn từ chối trình biên dịch một tối ưu hóa. Đọc về nó và tại sao nó có hại tại gcc.gnu.org/onlinedocs/gcc/… trong "-fstrict-aliasing". – hirschhornsalz

+1

Có, @drhirsh là đúng, đối với mẫu được cung cấp bởi @psihodelia giải pháp của tôi hoạt động, nhưng nó không thành công sau những thay đổi nhỏ do sự liên kết bị hỏng. –

5

Bạn đang quên rằng bạn cần phải diễn giải lại a như mảng nổi. Mã sau hoạt động đúng:

int main(){ 
    v4sf a,b,c; 
    a = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    b = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    c = (v4sf){0.1f,0.2f,0.3f,0.4f}; 
    a = b + c; 
    float* pA = (float*) &a; 
    printf("a=[%f %f %f %f]\n",pA[0], pA[1], pA[2], pA[3]); 
    return 0; 
} 

P.S .: cảm ơn câu hỏi này, tôi không biết rằng gcc có hỗ trợ SSE như vậy.

CẬP NHẬT: Giải pháp này không thành công khi mảng không có ký hiệu. Giải pháp được cung cấp bởi @drhirsh là miễn phí từ vấn đề này.

+0

omg THANK YOU SO MUCH !!! – psihodelia

+4

Loại punning là nguy hiểm. – hirschhornsalz

6

Lưu ý rằng gcc 4.6 tại supports vectơ subscripted:

Trong vectơ C có thể được subscripted như thể véc tơ là một mảng với cùng một số yếu tố và loại hình cơ bản. Trong số các truy cập bị ràng buộc, hãy gọi hành vi không xác định khi chạy. Cảnh báo cho truy cập bị ràng buộc cho đăng ký vector có thể được kích hoạt với -Barray-bounds.

+1

Điều này chỉ hoạt động trong C, không phải C++. Có một lỗi nổi bật: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51033 –

+1

@DavidGiven Giờ đây, được đánh dấu là cố định. –