2009-11-20 11 views
8

Di solito io lavoro con i vettori 3D utilizzando i seguenti tipi:C - Come accedere elementi del vettore utilizzando GCC SSE vettore estensione

typedef vec3_t float[3]; 

vettori di inizializzazione utilizzando smth. come:

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

e accedervi utilizzando smth. Mi piace:

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

Ora ho bisogno di un'aritmetica vettoriale utilizzando le istruzioni SSE. Ho il seguente codice:

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 supporta tale modo. Ma ... Innanzitutto, mi dà 0.00000 come risultato. Secondo, non posso accedere agli elementi di tali vettori. La mia domanda è: come posso accedere agli elementi di tali vettori? Ho bisogno di smth. come un [0] per accedere elemento X, un [1] per accedere elemento Y, ecc

PS: compilo questo codice utilizzando:

gcc -msse testgcc.c -o testgcc 
+0

Le domande non erano così difficili e non mi considero un esperto di GCC. La prossima volta usare un titolo più innocuo, ho quasi saltato la domanda. – hirschhornsalz

risposta

16

Il modo sicuro e consigliato per accedere agli elementi è con un'unione, anziché punire il tipo di puntatore, che blocca i meccanismi di rilevamento dell'aliasing del compilatore e può portare a codice instabile.

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

no, elder_george ha fornito un esempio più pratico: è abbastanza sicuro se si attua il suo consiglio in macro o in linea – psihodelia

+2

Sembra che non sia stato abbastanza chiaro. Digitare punire con i puntatori è sbagliato perché il dereferenziamento di un puntatore punteggiato tipicamente infrange le rigide regole di aliasing. Ciò si traduce in un comportamento indefinito. Non diventa più sicuro con l'inlining o il macro. Ma puoi usare l'opzione del compilatore _-fno-strict-aliasing_, che è fatta apposta per il codice spezzato come questo. I binari risultanti potrebbero essere un po 'più lenti, perché neghi al compilatore un'ottimizzazione. Leggilo e perché non funziona su gcc.gnu.org/onlinedocs/gcc/... sotto "-fstrict-aliasing". – hirschhornsalz

+1

Sì, @drhirsh ha ragione, per esempio fornito da @psihodelia la mia soluzione funziona, ma fallisce dopo piccole modifiche a causa dell'allineamento rotto. –

5

Stai dimenticando che è necessario reinterpretare a come serie di galleggianti. Il seguente codice funziona correttamente:

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 .: grazie per questa domanda, non sapevo che gcc ha tale supporto SSE.

AGGIORNAMENTO: questa soluzione ha esito negativo una volta che gli array non sono stati allineati. La soluzione fornita da @drhirsh è esente da questo problema.

+0

omg GRAZIE MOLTO !!! – psihodelia

+4

La punzonatura di tipo è pericolosa. – hirschhornsalz

6

noti che gcc 4.6 ora supports vettori con indice:

In C vettori possono essere indicizzato come se il vettore fosse un array con lo stesso numero di elementi e tipo di base. Gli accessi fuori limite invocano un comportamento indefinito in fase di esecuzione. Gli avvisi per gli accessi non vincolati per l'abbonamento vettoriale possono essere abilitati con -Warray-bounds.

+1

Funziona solo in C, non in C++. C'è un bug in sospeso: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51033 –

+1

@DavidGiven Ora è contrassegnato come fisso. –