|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Member
Iscritto dal: May 2006
Messaggi: 38
|
[C++] funzione memcpy
[Post modificato]
Salve a tutti! Ho re-implementato la funzione memcpy per cercare di capirne al meglio il significato e l'utilizzo. Codice:
// memcpy.cc #include <iostream> using namespace std; void* memcpy(void* s1, const void* s2, unsigned lenght) { const char* from = (const char*)s2; char* to = (char*)s1; while (lenght != 0) { *to++ = *from++; --lenght; } return s1; } int main() { char* src = "prova"; char* dest = new char[strlen(src)+1]; cout << "source: " << src << endl; char* result = (char*)memcpy(dest,src,strlen(src)+1); cout << "destination: " << result << endl; } Il puntatore to e' automatic, quindi lo spazio di memoria riservato alla stringa in stile C viene liberato dopo l'ultima istruzione return. In che modo si potrebbe utilizzare un indirizzo iniziale di una sequenza di caratteri alfanumerici gia' deallocata? ![]() Ultima modifica di riemann_01 : 31-05-2006 alle 13:27. |
![]() |
![]() |
![]() |
#2 | |
Senior Member
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
|
Quote:
Secondo le specifiche, memcpy deve ritornare il puntatore all'area di destinazione.
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%) |
|
![]() |
![]() |
![]() |
#3 |
Member
Iscritto dal: May 2006
Messaggi: 38
|
Grazie per la risposta immediata. Modifico subito la funzione!
|
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Ciao
il codice e' corretto. Hai pero' la possibilita' di eseguirlo piu' velocemente, a patto di complicare un po' l'algoritmo: invece di trasferire un byte alla volta, potresti trasferirne 4, ottimizzando i trasferimenti sul bus. Ovviamente devi prestare attenzione ai resti ed agli allineamenti, ma non e' difficile. High Flying Sottovento
__________________
In God we trust; all others bring data |
![]() |
![]() |
![]() |
#5 | |
Senior Member
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
|
Quote:
Comunque se si volesse implementarla in modo un po' più efficiente in "C", si può fare così: Codice:
typedef unsigned char VAL8; typedef unsigned long VAL32; void *my_memcpy (void *dest, const void *src, int length) { register VAL32 a, b; VAL32 *d = (VAL32*) dest; VAL32 *s = (VAL32*) src; VAL8 *d2, *s2; while (length >= 8) { a = *(s+0); b = *(s+1); *(d+0) = a; *(d+1) = b; s += 2; d += 2; length -= 8; } s2 = (VAL8*) s; d2 = (VAL8*) d; while (length-- > 0) *d2++ = *s2++; return dest; } ![]() EDIT: Aggiunto solo = nel test.
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%) Ultima modifica di andbin : 31-05-2006 alle 08:16. |
|
![]() |
![]() |
![]() |
#6 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
due cose:
1) il codice è sbagliato perché non tieni conto degli overlaps, mentre la versione originale lo fa 2) gli Intel hanno istruzioni che fanno tutto il lavoro; guarda per esempio le varie versioni di REP MOVS, credo che tengano anche conto degli overlaps |
![]() |
![]() |
![]() |
#7 | |||||
Senior Member
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
|
Quote:
![]() Quote:
Quote:
Quote:
Quote:
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%) |
|||||
![]() |
![]() |
![]() |
#8 | ||
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
![]() Quote:
![]() chissà perché lo standard del C prevede che la memmove gestisca gli overlap e la memcpy no... ![]() è troppo vecchio sto linguaggio, e Unix assieme ad esso; certe cose di Unix e del C sono abbastanza strane. |
||
![]() |
![]() |
![]() |
#9 | |
Member
Iscritto dal: May 2006
Messaggi: 38
|
Quote:
|
|
![]() |
![]() |
![]() |
#10 | |
Member
Iscritto dal: May 2006
Messaggi: 38
|
Quote:
Puoi postare il codice? |
|
![]() |
![]() |
![]() |
#11 | |
Senior Member
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
|
Quote:
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%) |
|
![]() |
![]() |
![]() |
#12 |
Member
Iscritto dal: May 2006
Messaggi: 38
|
Si, ma vorrei capire in che modo l'avrebbe implementato lui! Non te la prendere!
Ho studiato il tuo codice e l'ho apprezzato! ![]() Una domanda: perche' hai usato come class-storage per a e b register? Non viene quasi sempre ignorato dal compilatore? Ultima modifica di riemann_01 : 31-05-2006 alle 12:55. |
![]() |
![]() |
![]() |
#13 | ||
Senior Member
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
|
Quote:
Quote:
Io ce l'ho messo il register ... se poi il compilatore lo ignora e se ne frega ... non ci posso fare nulla. ![]() ![]()
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%) |
||
![]() |
![]() |
![]() |
#14 |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Codice:
char dest[strlen(src)+1]; Ad es. il compilatore Microsoft mi sembra che rifiuti questa sintassi. Codice:
char* result = (char*)memcpy(dest,src,sizeof(src)+1); E' un caso se ti funziona.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
![]() |
![]() |
![]() |
#15 |
Member
Iscritto dal: May 2006
Messaggi: 38
|
to: andbin
Un'altra domanda che mi e' venuta in mente in questo momento.
Sebbene con la tua versione si possano copiare 4 bytes per volta questo pero' comporta un incremento delle variabili locali utilizzate. Per valutare la complessita' della funzione non occorre tenere in conto anche le risorse di memorizzazione oltre che il numero di operazioni eseguite? Ultima modifica di riemann_01 : 31-05-2006 alle 13:28. |
![]() |
![]() |
![]() |
#16 |
Member
Iscritto dal: May 2006
Messaggi: 38
|
to: sensine
E' solo un caso fortuito, in effetti, che il programma funzioni: la stringa src e' composta da cinque caratteri.
Queste modifiche dovrebbero rendere il codice privo di errori: Codice:
char* dest = new char[strlen(src)+1]; Codice:
char* result = (char*)memcpy(dest,src,strlen(src)+1); Grazie a tutti per il supporto! ![]() |
![]() |
![]() |
![]() |
#17 |
Senior Member
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
|
Ciao a riemann_01 e a tutti gli altri
scusate la risposta un po' in ritardo, ma e' per il fuso orario. Visto che e' stato richiesto, provo a postare una mia versione. Purtroppo non l'ho provata, ma qualche mese fa ho fatto una prova con un codice simile, per cui sono piuttosto sicuro (errori di codifica a parte) delle prove di ottimizzazione: Codice:
void *my_memcpy (void *dst, void *src, int nbytes) { register char *r_dst = (char *)dst; register char *r_src = (char *)src; int n = nbytes / 4; int remaining = nbytes % 4; register int i; register char *p; register char *q; for (i = n; i; --i) *r_dst++ = *r_src++; p = (char *)r_dst; q = (char *)r_src; for (i = remaining; i; --i) *p++ = *q++; return dst; } Il processore e' un simil-Motorola, con un set di istruzioni quasi uguale. Il compilatore onora le variabili registro nell'ordine in cui le trova, partendo dalle prime dichiarate e fintanto che puo'. L'idea e' quella di fare un ciclo 4 volte piu' corto. Rispetto ad AndBin, utilizzo solo post-incrementi perche' sono andato a vedere il codice assembler generato: il processore in uso, infatti, ha una istruzione di post-incremento di registro, pertanto posso risolvere il ciclo con il minore numero di istruzioni possibile. Esiste anche l'istruzione di pre-decremento di un registro, che quindi e' stata utilizzata per il ciclo for. Inoltre il confronto con zero e' piu' veloce, per cui il ciclo che conta al rovescio risulta piu' efficiente (sulla mia macchina, ovviamente). Sempre sulla mia macchina, per inciso, l'istruzione a++ e l'istruzione a += 1 vengono risolte con un codice diverso, con il risultato che il primo e' piu' veloce del secondo. Questa tecnica era gia' usata sui primi Macintosh con processore 680x0, visto il set di istruzioni a disposizione (e visto che era spiegata nei libri della serie "Inside Macintosh"). E' uno dei casi in cui l'implementazione C ha una rappresentazione praticamente 1 a 1 con l'assembler, pertanto la codifica in assembler non porta alcun vantaggio. Scusate eventuali errori. A disposizione per le correzioni High Flying Sottovento
__________________
In God we trust; all others bring data |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 13:57.