2009-11-20 2 views
8

Normalerweise arbeite ich mit 3D-Vektoren folgenden Typen verwenden:C - Wie Elemente des Vektors zuzugreifen Vektor mit GCC SSE Erweiterung

typedef vec3_t float[3]; 

Initialisierung Vektoren smth. wie:

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

und Zugriff auf sie mit etw. wie:

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

Jetzt brauche ich eine Vektorarithmetik mit SSE-Anweisungen. Ich habe folgenden Code:

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 unterstützt so. Aber ... Zuerst gibt es mir 0,00000 als Ergebnis. Zweitens kann ich nicht auf die Elemente solcher Vektoren zugreifen. Meine Frage ist: Wie kann ich auf Elemente solcher Vektoren zugreifen? Ich brauche etwas. wie ein [0] X-Element zuzugreifen, ein [1] Y Element zuzugreifen usw.

PS: Ich habe diesen Code kompilieren:

gcc -msse testgcc.c -o testgcc 
+0

Die Fragen waren nicht so schwer, und ich betrachte mich selbst nicht als GCC-Experte. Beim nächsten Mal verwende ich einen harmloseren Titel, ich habe die Frage fast übersprungen. – hirschhornsalz

Antwort

16

Der sichere und empfohlene Weg, um auf die Elemente zuzugreifen, ist mit einer Union anstelle von Pointer-Punning, die Aliasing-Erkennungsmechanismen des Compilers überlisten und zu instabilem Code führen können.

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

Nein, elder_george hat ein praktischeres Beispiel gegeben - es ist sicher genug, wenn Sie seinen Rat in einem Makro oder in einem Inline-Code implementieren – psihodelia

+2

Es scheint, dass ich nicht klar genug war. Typ punning mit Zeigern ist schlecht, da die Dereferenzierung eines type-punted-Zeigers strikte Alias-Regeln bricht. Dies führt zu undefiniertem Verhalten. Es wird nicht sicherer durch Inlining oder Makroing. Aber Sie können die Compileroption _-fno-strict-aliasing_ verwenden, die genau für diesen Code gemacht wird. Die resultierenden Binärdateien können etwas langsamer sein, da Sie dem Compiler eine Optimierung verweigern. Lesen Sie darüber und warum es schlecht ist bei gcc.gnu.org/onlinedocs/gcc/... unter "-fstrict-aliasing". – hirschhornsalz

+1

Ja, @drhirsh ist richtig, für die Probe, die von @psihodelia bereitgestellt wird, funktioniert meine Lösung, aber es schlägt nach kleinen Änderungen wegen der unterbrochenen Ausrichtung fehl. –

5

Sie vergessen, dass Sie neu zu interpretieren müssen a als Reihe von Schwimmern. Folgenden Code funktioniert:

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 .: Danke für diese Frage, ich wusste nicht, dass gcc solche SSE-Unterstützung hat.

UPDATE: Diese Lösung schlägt fehl, sobald die Arrays nicht ausgerichtet wurden. Lösung von @drhirsh ist frei von diesem Problem.

+0

omg DANKE SO VIEL !!! – psihodelia

+4

Typ Punning ist gefährlich. – hirschhornsalz

6

anzumerken, dass gcc 4.6 jetzt supports subscripted Vectors:

In C Vektoren subscripted wie sein kann, wenn der Vektor ein Array mit der gleichen Anzahl von Elementen und Basistyp ist. Ungebundene Zugriffe rufen zur Laufzeit undefiniertes Verhalten auf. Warnungen für nicht-barrierefreie Zugriffe für die Vektor-Subskription können mit -Warray-Grenzen aktiviert werden.

+1

Dies funktioniert nur in C, nicht in C++. Es gibt einen herausragenden Fehler: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51033 –

+1

@DavidGiven Es ist jetzt als behoben markiert. –

Verwandte Themen