Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Affidabilità di alcune macro
Forum - C/C++ - Affidabilità di alcune macro

Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 21:49
Martedì, 03/10/2017
Buonasera programmatori!

Sono attanagliato da dubbi circa l'affidabilità di alcune macro di manipolazione dei bit in valori numeri con dimensione non uniforme (8, 16, 32 e 64 bit) che vorrei usare in uno di quei tanti esperimenti inconcludenti che di quando in quando mi vengono in mente.

Ho messo insieme un programmino di prova nel quale SEMBRA che tutto funzioni ma, siccome in altri casi ho fatto delle MOSTRUOSITA' che funzionavano nel caso particolare ma erano inaffidabili nella generalità, vi chiedo cortesemente un'opinione. In caso ci siano dei difetti, sareste così gentili da aiutarmi a capire cosa ho sbagliato?

Vai col codice!

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4.  
  5. // per intervenire sui singoli bit di un
  6. // valore numerico con un massimo di 64 bit
  7. #define SETBIT(n,nBit) ((n)|(((uint64_t)(1))<<(nBit)))
  8. #define UNSETBIT(n,nBit) ((n)&(~(((uint64_t)(1))<<(nBit))))
  9. #define INVERTBIT(n,nBit) ((n)^(((uint64_t)(1))<<(nBit)))
  10.  
  11. void stampa_binario( uint64_t n, uint8_t nBitMin );
  12.  
  13. int main() {
  14.     uint8_t  n8  = 20;
  15.     uint32_t n32 = 1234567;
  16.  
  17.     // prova valore a 8 bit
  18.     stampa_binario( n8, 8 ); putchar( '\n' );
  19.  
  20.     n8 = SETBIT( n8, 6 );
  21.     stampa_binario( n8, 8 ); putchar( '\n' );
  22.  
  23.     n8 = UNSETBIT( n8, 6 );
  24.     stampa_binario( n8, 8 ); putchar( '\n' );
  25.  
  26.     n8 = INVERTBIT( n8, 6 );
  27.     stampa_binario( n8, 8 ); putchar( '\n' );
  28.  
  29.     // prova valore a 32 bit
  30.     stampa_binario( n32, 32 ); putchar( '\n' );
  31.  
  32.     n32 = SETBIT( n32, 6 );
  33.     stampa_binario( n32, 32 ); putchar( '\n' );
  34.  
  35.     n32 = UNSETBIT( n32, 6 );
  36.     stampa_binario( n32, 32 ); putchar( '\n' );
  37.  
  38.     n32 = INVERTBIT( n32, 6 );
  39.     stampa_binario( n32, 32 ); putchar( '\n' );
  40.  
  41.     return 0;
  42. }
  43.  
  44. void stampa_binario( uint64_t n, uint8_t nBitMin ) {
  45.     char s[68];
  46.     uint8_t i=0;
  47.  
  48.     do {
  49.         s[i++] = n%2?'1':'0';
  50.         n >>= 1;
  51.     } while( n != 0 );
  52.  
  53.     while( i < nBitMin )
  54.         s[i++] = '0';
  55.     s[i] = '\0';
  56.  
  57.     while( i>0 ) putchar( s[--i] );
  58. }



ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 22:41
Martedì, 03/10/2017
Il codice è giusto, ovviamente per valori di n ragionevoli e con i soliti accorgimenti per quando si usano le macro.

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 9:11
Mercoledì, 04/10/2017
Sì, per "valori ragionevoli" intendiamo la gamma possibile entro un certo numero di bit (tipo 0-255 per gli 8 bit, ecc.), questo lo davo per assodato.

I "soliti accorgimenti"... intendo la cosa in questo modo: tenere presente che "invocare" una macro è come trascrivere il testo della macro stessa nel punto esatto in cui la "invochi" (tenendo presente che i "parametri" vengono inseriti per "sostituzione" nel testo stesso), giusto?E' sufficiente?

Forse è meglio che faccia un esempio più esplicito, che coi giri di parole rischio di non essere chiaro (problemi col lessico tecnico, che conosco solo a spanne).

Codice sorgente - presumibilmente C/C++

  1. uint16_t val = 0;
  2.  
  3. // scrivere cosi'...
  4.  
  5. val = SETBIT( val, 2 );
  6.  
  7. // ... e' come scrivere ESATTAMENTE cosi',
  8. // nello stesso punto del codice...
  9.  
  10. val = ((val)|(((uint64_t)(1))<<(2)));
  11.  
  12. // dando come risultato 0000000000000100, cioe' 4



ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 15:14
Giovedì, 05/10/2017
Sì, direi che non c'è molto da aggiungere, se non che forse si potrebbe anche usare una funzione inline in questo caso, il compilatore non dovrebbe avere problemi a generare un codice ottimizzato allo stesso modo.

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 19:09
Giovedì, 05/10/2017
Bene! Grazie per le rassicurazioni, ora posso usare più a cuor leggero quelle "scorciatoie".

Ultima modifica effettuata da AldoBaldo il 05/10/2017 alle 19:10


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote