|
#1
|
|
|
|
|
Nelle mie applicazioni mi ritrovo spesso a dover passare ad una funzione il
puntatore ad un buffer in memoria. Come ho visto fare nelle varie funzioni di libreria (vedi memcpy e simili), ho pensato di dichiarare il buffer come (void *). In questo modo, il chiamante può passare un qualsiasi puntatore, senza fare cast. All'interno della funzione, però, devo accedere al buffer scrivendolo byte a byte e quindi mi serve un (unsigned char *). Normalmente faccio così: void dummy( void *bufp ) { unsigned char *buf = bufp; *bufp++ = 0xAA; *bufp++ = 0xAB; .. Ma così perdo spazio sullo stack per bufp e per buf e mi sembra abbastanza inutile. |
|
|
|
#2
|
|
|
|
|
pozz wrote:
> Nelle mie applicazioni mi ritrovo spesso a dover passare ad una funzione > il puntatore ad un buffer in memoria. Come ho visto fare nelle varie > funzioni di libreria (vedi memcpy e simili), ho pensato di dichiarare il > buffer come (void *). > > In questo modo, il chiamante può passare un qualsiasi puntatore, senza > fare cast. > > All'interno della funzione, però, devo accedere al buffer scrivendolo > byte a byte e quindi mi serve un (unsigned char *). > Normalmente faccio così: > void dummy( void *bufp ) { > unsigned char *buf = bufp; > *bufp++ = 0xAA; > *bufp++ = 0xAB; > .. > Ma così perdo spazio sullo stack per bufp e per buf e mi sembra > abbastanza inutile. Probabilmente il compilatore se ne accorge e non ti fa perdere spazio per niente... In C++ userei invece un riferimento, in questo caso... E. |
|
#3
|
|
|
|
|
On 01/26/08 20:22, pozz wrote:
> Nelle mie applicazioni mi ritrovo spesso a dover passare ad una funzione > il puntatore ad un buffer in memoria. Come ho visto fare nelle varie > funzioni di libreria (vedi memcpy e simili), ho pensato di dichiarare il > buffer come (void *). > > In questo modo, il chiamante può passare un qualsiasi puntatore, senza > fare cast. > > All'interno della funzione, però, devo accedere al buffer scrivendolo > byte a byte e quindi mi serve un (unsigned char *). > Normalmente faccio così: > void dummy( void *bufp ) { > unsigned char *buf = bufp; > *bufp++ = 0xAA; > *bufp++ = 0xAB; > .. > Ma così perdo spazio sullo stack per bufp e per buf e mi sembra > abbastanza inutile. Forse volevi scrivere: void dummy( void *bufp ) { unsigned char *buf = bufp; *buf++ = 0xAA; *buf++ = 0xAB; .. In ogni caso se vuoi evitare di allocare una variabile nello stack puoi usare il cast: void dummy(void *bufp) { *((char *)bufp++) = 0xAA; *((char *)bufp++) = 0xAB; .... } Ciao Giovanni |
|
#4
|
|
|
|
|
?manu* ha scritto:
> pozz wrote: In realtà l'esempio che volevo scrivere è sbagliato. Lì sopra bisogna leggere (*buf++ = ...) e non (*bufp++ = ...) >> Ma così perdo spazio sullo stack per bufp e per buf e mi sembra >> abbastanza inutile. > > Probabilmente il compilatore se ne accorge e non ti fa perdere spazio > per niente... In C++ userei invece un riferimento, in questo caso... Sì, ci avevo pensato. Però ammettendo che il compilatore se ne accorga, non mi sembra uno stile di programmazione molto pulito... o sbaglio? Come farebbe una memcpy(), per esempio? |
|
#5
|
|
|
|
|
pozz <pNoOzSzPuAgMno> wrote:
> Ma così perdo spazio sullo stack per bufp e per buf e mi sembra > abbastanza inutile. Perdi 4 o 8 byte per un puntatore in più nella peggiore delle ipotesi. Sicuro che sia inaccettabile? Aggiungo altre note... se conosci giù quello che ci devi scrivere, perchè non ne fai un array di letterali ({0xAA, 0xAB, ...}) e lo copi proprio con memcpy? Se non usi questa strada, perchè non fattibile, io considererei l'alternativa di una macro (da poi fare sparire) al posto di *((char *)bufp++) = 0xAB; #define SIGNIFICATIVE_NAME(pvoid, value) \ *((char *)(pvoid)++) = (value); E a questo punto scavalli il tutto. Ovviamente a patto di trovare un nome significativo che renda *effettivamente* il codice più leggibile. |
|
#6
|
|
|
|
|
"Giovanni" <lsodgf0> ha scritto nel messaggio
news:jag1 > On 01/26/08 20:22, pozz wrote: > > Forse volevi scrivere: > void dummy( void *bufp ) { > unsigned char *buf = bufp; > *buf++ = 0xAA; > *buf++ = 0xAB; > .. > > In ogni caso se vuoi evitare di allocare una variabile nello stack > puoi usare il cast: > void dummy(void *bufp) > { > > *((char *)bufp++) = 0xAA; > *((char *)bufp++) = 0xAB; > .... > } Attenzione che non compila! Il ++ viene associato direttamente a bufp non a (char *)bufp Io preferisco la versione con la temporanea. Più pulito. |
|
#7
|
|
|
|
|
"crxor 666" <riko> ha scritto nel messaggio
news:riko > pozz <pNoOzSzPuAgMno> wrote: > > > Ma così perdo spazio sullo stack per bufp e per buf e mi sembra > > abbastanza inutile. > > Perdi 4 o 8 byte per un puntatore in più nella peggiore delle ipotesi. > Sicuro che sia inaccettabile? > > Aggiungo altre note... se conosci giù quello che ci devi scrivere, > perchè non ne fai un array di letterali ({0xAA, 0xAB, ...}) e lo copi > proprio con memcpy? Questa è un'idea. > > Se non usi questa strada, perchè non fattibile, io considererei > l'alternativa di una macro (da poi fare sparire) al posto di > > *((char *)bufp++) = 0xAB; Stesso problema del post di Giovanni. > > #define SIGNIFICATIVE_NAME(pvoid, value) \ > *((char *)(pvoid)++) = (value); > Idem. |
|
#8
|
|
|
|
|
On 01/27/08 13:09, Giorgio Silvestri wrote:
>> In ogni caso se vuoi evitare di allocare una variabile nello stack >> puoi usare il cast: >> void dummy(void *bufp) >> { >> >> *((char *)bufp++) = 0xAA; >> *((char *)bufp++) = 0xAB; >> .... >> } > > Attenzione che non compila! Puoi sempre riscriverlo con un ulteriore livello di parentesi: *(((char *)bufp)++) = .... ma compila (e funziona) perfettamente con il gcc anche senza le parentesi. Ma ti posso assicurare che funziona tutti i compilatori. > Il ++ viene associato direttamente a bufp non a (char *)bufp No. Il ++ viene associato al lvalue che lo precede e che è bufp ma con il cast, cioè: (char *)bufp > Io preferisco la versione con la temporanea. > Più pulito. Su questo sono d'accordo. Ciao Giovanni |
|
#9
|
|
|
|
|
Giorgio Silvestri <giorgiosilvestri> wrote:
> > Se non usi questa strada, perchè non fattibile, io considererei > > l'alternativa di una macro (da poi fare sparire) al posto di > > > > *((char *)bufp++) = 0xAB; > > Stesso problema del post di Giovanni. Vero. Non ci avevo pensato (ne lo avevo provato). Il fix è banale. Ma non piace neppure a me. Io personalmente userei proprio il memcpy. Si sa mica mai che se lo siano ottimizzato per bene. |
|
#10
|
|
|
|
|
Giovanni ha scritto:
> On 01/26/08 20:22, pozz wrote: > > Forse volevi scrivere: > void dummy( void *bufp ) { > unsigned char *buf = bufp; > *buf++ = 0xAA; > *buf++ = 0xAB; > .. Sì sì, hai ragione. > In ogni caso se vuoi evitare di allocare una variabile nello stack puoi > usare il cast: > void dummy(void *bufp) > { > > *((char *)bufp++) = 0xAA; > *((char *)bufp++) = 0xAB; > .... > } Giusto, però così diventa difficile da leggere e complicato da scrivere. Poi quelle istruzioni sono solo un esempio. In alcuni casi devo scrivere dei byte con valore fisso, in altri casi devo copiare (mediante memcpy) delle variabili, in altri casi delle struct, ecc. |
|
#11
|
|
|
|
|
crxor 666 ha scritto:
> pozz <pNoOzSzPuAgMno> wrote: > >> Ma così perdo spazio sullo stack per bufp e per buf e mi sembra >> abbastanza inutile. > > Perdi 4 o 8 byte per un puntatore in più nella peggiore delle ipotesi. > Sicuro che sia inaccettabile? Su microcontrollori con 100 byte di RAM è inaccettabile. > Aggiungo altre note... se conosci giù quello che ci devi scrivere, > perchè non ne fai un array di letterali ({0xAA, 0xAB, ...}) e lo copi > proprio con memcpy? Non è sempre così. In alcuni casi devo scrivere dei byte letterali, in altri casi delle variabili, in altri devo copiare delle struct e in altri ancora ho un mix di queste operazioni da fare sul buffer. > Se non usi questa strada, perchè non fattibile, io considererei > l'alternativa di una macro (da poi fare sparire) al posto di > > *((char *)bufp++) = 0xAB; > > #define SIGNIFICATIVE_NAME(pvoid, value) \ > *((char *)(pvoid)++) = (value); > > E a questo punto scavalli il tutto. Ovviamente a patto di trovare un > nome significativo che renda *effettivamente* il codice più leggibile. E' un'idea... |
|
#12
|
|
|
|
|
On 01/27/08 15:42, pozz wrote:
> Giusto, però così diventa difficile da leggere e complicato da > scrivere. Poi quelle istruzioni sono solo un esempio. In alcuni > casi devo scrivere dei byte con valore fisso, in altri casi devo > copiare (mediante memcpy) delle variabili, in altri casi delle > struct, ecc. Sul fatto che sia più complicato da scrivere e difficile da leggere concordo, ma se ti preoccupi di risparmiare anche il singolo byte di memoria è conveniente. Qualsiasi operazione tu debba fare il cast la può risolvere. Per semplificare la scritture puoi usare delle macro: #define bufp_c ((char *)bufp) /* puntatore a char */ #define bufp_i ((int *)bufp) /* puntatore a int */ #define bufp_s ((struct s *)bufp) /* puntatore a struct s */ *(bufp_c)++ = 0x04 *(bufp_i)++ = 123456; *(bufp_s)->membro_struttura = .... #undef bufp_s #undef bufp_i #undef bufp_c L'unico side effect che vedo è il fatto che in questi esempi vai a modificare il valore del parametro di ingresso. In certe situazioni ed accessi multipli potrebbe servire il valore originale. Tieni anche presente che usando l'ottimizzazione molti compilatori mettono la variabile in un registro ed anche tu lo puoi fare con la keyword register nella dichiarazione della puntatore d'appoggio. Attenzione però che a volte se la funzione è molto complessa, il compilatore ha bisogno dei registri ed usa lo stack per salvare temporaneamente il registro e non risparmia nulla. Ciao Giovanni |
|
#13
|
|
|
|
|
Giovanni <lsodgf0> wrote:
> Tieni anche presente che usando l'ottimizzazione molti compilatori > mettono la variabile in un registro ed anche tu lo puoi fare con la > keyword register nella dichiarazione della puntatore d'appoggio. Tipicamente non farci conto: il compilatore fa un po' quello che vuole. Non essendo tenuto a rispettare la direttiva, in molti i casi la ignora e punto. :) |
|
#14
|
|
|
|
|
On 01/27/08 17:22, crxor 666 wrote:
> >> Tieni anche presente che usando l'ottimizzazione molti >> compilatori mettono la variabile in un registro ed anche tu lo >> puoi fare con la keyword register nella dichiarazione della >> puntatore d'appoggio. > > Tipicamente non farci conto: il compilatore fa un po' quello che > vuole. Non essendo tenuto a rispettare la direttiva, in molti i > casi la ignora e punto. :) > Difatti avevo scritto anche: >> Attenzione però che a volte se la funzione è molto complessa, il >> compilatore ha bisogno dei registri ed usa lo stack per salvare >> temporaneamente il registro e non risparmia nulla. Ciao Giovanni |
|
#15
|
|
|
|
|
La soluzione piu' elegante, secondo il mio modesto parere, e' che
invece di dichiarare la tua funzione come se accettasse dei void *, dovresti dichiararla con char *. Motivo: la tua funzione e' effettivamente una funzione che opera con l'aritmetica dei puntatori. Per cui la tua funzione ha bisogno di accedere ai byte. Il chiamante della tua funzione e' quello che si deve preoccupare di fare il cast. Dal punto di vista del compilatore e' piu' facile ottimizzare l'allineamento dei byte sul chiamante che sul chiamato. Perche' ricordati, con la dichiarazione void * stai chiedendo al compilatore di accettare *sempre* un puntatore con allineamento generico. Siccome accedi ai singoli byte, se non ti fidi dell'ottimizzazione del compilatore, effettivamente tu stai chiedendo al compilatore una cosa non vera. Tu hai bisogno, nella tua funzione, di avere un puntatore con massima efficienza ad accesso di byte sequenziale. Il compilatore ha piu' facilita' a capire la cosa nel codice chiamante, in quanto il cast viene fatto una sola volta, e il chiamante puo' usare ottimizzazioni piu' idonee per farlo. Le implementazioni di memcpy che vedo in giro infatti contano sul fatto che il processore possa fare delle copie _in blocco_, senza quindi accedere ai singoli byte. Le funzioni che operano su byte singoli di regola dichiarano i loro puntatori come char *, e sta al chiamante decidere se la chiamata e' opportuna o c'e' bisogno di un cast. Dal punto di vista dell'interfaccia, che strcpy sia dichiarato con char * mi fa capire che si sta parlando di byte signoli. Void * mi fa capire che sia generico e quindi non ottimizzato per la mia particolare struttura dati. Questo e' il mio EURO 0.02 |
|
|
|
|
| Discussioni simili | |
| Da una stringa di byte ad array di byte Salve a tutti, con byte[] IV = Encoding.ASCII.GetBytes("arcobaleno"); ottengo una serie di numeri "97,114,99,111,98,97,108,101,110,11" che conservo nel web.config per... |
|
| come posso spostare un byte all'interno di un'altro byte? mi spiego,ho 2 byte già definiti(tipo:11110000 e 10001000)e voglio che il secondo byte entri parzialmente nel primo occupandone i primi 3 bit ,quindi con un byte risultante... |
|
| Integer=byte*byte [OVERFLOW?] Ciao a tutti il seguente codice Dim nRighe As Byte Dim nColonne As Byte Dim nElementi As Integer Dim i As Byte Dim ii As Byte Dim index As Integer |
|
| Oggetto Buffer as Byte: LENGHT??? Scusate, forse è una domanda troppo idiota... Se io dichiaro dim buffer (1024) as byte quanti caratteri potrò metterci dentro? Secondo quello che ho scoperto sarebbe 3... |
|
| prendere i byte in parole di 2 byte Salve a tutti. Ho un problema che non so risolvere. Ho bisogno di codificare una sequenza numerica in un'altra sequenza numerica. Mi spiego meglio. Supponiamo di aver... |
|
|
Tutti gli orari sono GMT. Attualmente sono le 01:43. | Privacy Policy
|