Weil es gerade dazu passt:
Hier steht, dass man jedem eigenständigen Datensatz auch einen eigenen Typ geben soll.
z.B.
Code: Alles auswählen
struct Firstname
{
char value[64];
};
Code: Alles auswählen
struct Firstname
{
char value[64];
};
Ich kann keine Garantie für alle Compiler übernehmen, aber Du kannst Dir die Wahrscheinlichkeit selbst ausdenken:Nemo hat geschrieben:Weil es gerade dazu passt:
Hier steht, dass man jedem eigenständigen Datensatz auch einen eigenen Typ geben soll.
z.B.Werden solche Hüllstrukturen auch vom Optimierer entferntCode: Alles auswählen
struct Firstname { char value[64]; };
Code: Alles auswählen
struct Firstname fname;
char * result = fname.value;
Wenn es auf Geschwindigkeit ankommt, arbeitet man nicht mehr mit Strings.Nemo hat geschrieben:, oder sollte man die, wenn es auf Geschwindigkeit ankommt, zum Testen verwenden und für die endgültige Version wieder entfernen?
Aha, vielleicht könntest du das in das Tutorial einbauen. Ich kann mir das ganze durch diese Erklärung viel besser vorstellen.Xin hat geschrieben:Nehmen wir an, fname liegt an Adresse 1000 im Speicher. Um nun vom Beginn der Struktur bis zu "value" zu gelangen muss man alle vorherigen Elemente überspringen. Es gibt 0 Elemente, die zu überspringen sind, also wird 0 addiert und man hat die Adresse gefunden, an der "value" liegt: 1000.
Und wie genau prüft man das? Einmal mit und einmal ohne Hüllstruktur compilieren und dann überprüfen ob der gleiche Maschinencode dabei rauskommt?Xin hat geschrieben:Dass der Compiler eine Addition mit dem statischen Wert 0 nicht heraus optimiert, kann ich Dir nicht garantieren. Ich kann Dir aber garantieren, dass es nicht viel Aufwand ist, das zu prüfen.
Das ist schon klar, war ja nur ein Beispiel.Xin hat geschrieben:Wenn es auf Geschwindigkeit ankommt, arbeitet man nicht mehr mit Strings.Nemo hat geschrieben:, oder sollte man die, wenn es auf Geschwindigkeit ankommt, zum Testen verwenden und für die endgültige Version wieder entfernen?
Ähh... ich versuche es mir zu merken. ^^ (bzw. auf die Todoliste zu setzen ^^)Nemo hat geschrieben:Aha, vielleicht könntest du das in das Tutorial einbauen. Ich kann mir das ganze durch diese Erklärung viel besser vorstellen.Xin hat geschrieben:Nehmen wir an, fname liegt an Adresse 1000 im Speicher. Um nun vom Beginn der Struktur bis zu "value" zu gelangen muss man alle vorherigen Elemente überspringen. Es gibt 0 Elemente, die zu überspringen sind, also wird 0 addiert und man hat die Adresse gefunden, an der "value" liegt: 1000.
Genau.Nemo hat geschrieben:Und wie genau prüft man das? Einmal mit und einmal ohne Hüllstruktur compilieren und dann überprüfen ob der gleiche Maschinencode dabei rauskommt?Xin hat geschrieben:Dass der Compiler eine Addition mit dem statischen Wert 0 nicht heraus optimiert, kann ich Dir nicht garantieren. Ich kann Dir aber garantieren, dass es nicht viel Aufwand ist, das zu prüfen.
Code: Alles auswählen
xin@prgn:~$ cat dotvalue.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct FirstName
{
char Value[64];
};
void swapChar( char * value )
{
unsigned int i=0;
while( value[i] )
{
if( value[i] >= 'a' && value[i] <= 'z' )
value[i] -= 32;
else if( value[i] >= 'A' && value[i] <= 'Z' )
value[i] += 32;
i++;
}
}
void swapFirstName( struct FirstName * value )
{
unsigned int i=0;
while( value->Value[i] )
{
if( value->Value[i] >= 'a' && value->Value[i] <= 'z' )
value->Value[i] -= 32;
else if( value->Value[i] >= 'A' && value->Value[i] <= 'Z' )
value->Value[i] += 32;
i++;
}
}
int main( int argc, char ** argv )
{
if( argc != 4 )
{
printf( "%s <count> <method> <string>\nmethod: 0 for char *; 1 for struct FirstName *\n\nArgCount: %d - must be 3\n", argv[0], argc );
return EXIT_FAILURE;
}
unsigned int count = strtoul( argv[1], NULL, 10 );
printf( "Count: %u\n", count );
unsigned int method = strtoul( argv[2], NULL, 10 );
switch( method )
{
case 0:
{
printf( "Method: char *\n" );
char buffer[64];
strcpy( buffer, argv[3] );
printf( "Start : %s\n", buffer );
while( count-- )
swapChar( buffer );
printf( "Result: %s\n", buffer );
return EXIT_SUCCESS;
}
case 1:
{
printf( "Method: struct FirstName *\n" );
struct FirstName fname;
strcpy( fname.Value, argv[3] );
printf( "Start: %s\n", fname.Value );
while( count-- )
swapFirstName( &fname );
printf( "Result: %s\n", fname.Value );
return EXIT_SUCCESS;
}
default:
{
printf( "unknown method\n" );
return EXIT_FAILURE;
}
};
}
xin@prgn:~$
Code: Alles auswählen
xin@prgn:~$ gcc dotvalue.c
xin@prgn:~$ time ./a.out 30000001 0 "Hello proggen.org"
Count: 30000001
Method: char *
Start : Hello proggen.org
Result: hELLO PROGGEN.ORG
real 0m11.220s
user 0m9.385s
sys 0m0.012s
xin@prgn:~$ time ./a.out 30000001 0 "Hello proggen.org"
Count: 30000001
Method: char *
Start : Hello proggen.org
Result: hELLO PROGGEN.ORG
real 0m9.463s
user 0m9.413s
sys 0m0.004s
xin@prgn:~$ time ./a.out 30000001 1 "Hello proggen.org"
Count: 30000001
Method: struct FirstName *
Start: Hello proggen.org
Result: hELLO PROGGEN.ORG
real 0m8.286s
user 0m8.289s
sys 0m0.000s
xin@prgn:~$ time ./a.out 30000001 1 "Hello proggen.org"
Count: 30000001
Method: struct FirstName *
Start: Hello proggen.org
Result: hELLO PROGGEN.ORG
real 0m11.017s
user 0m8.285s
sys 0m0.000s
xin@prgn:~$ gcc -O9 dotvalue.c
xin@prgn:~$ time ./a.out 30000001 0 "Hello proggen.org"
Count: 30000001
Method: char *
Start : Hello proggen.org
Result: hELLO PROGGEN.ORG
real 0m3.556s
user 0m3.276s
sys 0m0.008s
xin@prgn:~$ time ./a.out 30000001 0 "Hello proggen.org"
Count: 30000001
Method: char *
Start : Hello proggen.org
Result: hELLO PROGGEN.ORG
real 0m3.447s
user 0m3.284s
sys 0m0.000s
xin@prgn:~$ time ./a.out 30000001 1 "Hello proggen.org"
Count: 30000001
Method: struct FirstName *
Start: Hello proggen.org
Result: hELLO PROGGEN.ORG
real 0m3.691s
user 0m3.324s
sys 0m0.000s
xin@prgn:~$ time ./a.out 30000001 1 "Hello proggen.org"
Count: 30000001
Method: struct FirstName *
Start: Hello proggen.org
Result: hELLO PROGGEN.ORG
real 0m3.742s
user 0m3.324s
sys 0m0.000s
xin@prgn:~$
Code: Alles auswählen
if( method )
{
struct FirstName fname;
strcpy( fname.Value, argv[3] );
printf( "Start: %s\n", fname.Value );
printf( "stru\n" );
while( count-- )
swapFirstName( &fname );
printf( "Result: %s\n", fname.Value );
return EXIT_SUCCESS;
}
else
{
char buffer[64];
strcpy( buffer, argv[3] );
printf( "Start : %s\n", buffer );
printf( "Char\n" );
while( count-- )
swapChar( buffer );
printf( "Result: %s\n", buffer );
return EXIT_SUCCESS;
}
Das Switch tut bei Millionen swap-Aufrufen nicht wehNemo hat geschrieben:Ich hab das Programm etwas abgeändert, um die Messung genauer zu machen:
time ist nur eine Näherung, keine wirklich gute Messung!Nemo hat geschrieben:Dann hab ich es mit -O3 compiliert und mit größeren Werten gefüttert. Ich hab das ganze dann 15 mal mit beiden Methoden durchlaufen lassen und war vom Ergebnis ziemlich überrascht:
Die Methode mit Hüllstruktur ist durchschnittlich um 9% schneller!
Ich habe auch dein Originalprogramm compiliert und ausgeführt und die Methode mit der Hüllstruktur war schon wieder schneller.
Das konnte ich mir nicht erklären also habe ich beide Programme ohne optimierung compiliert, wodurch wie erwartet die Methode mit Hüllstruktur deutlich langsamer war.
Ich habe keine Ahnung was der Compiler da macht aber durch das optimieren wird die Funktion mit der Hüllstruktur schneller als die Funktion mit dem Char-Array. Hat irgendwer eine Ahnung warum
Code: Alles auswählen
gcc dotvalue.c -S -fverbose-asm