Newsgroup: it.comp.lang.c
Titolo: operare sui bit

volevo sapere se č possibile tramite una funzione esistente vedere un char
come una matrice di 8 bit e operare sui singoli bit a piacimento, ovviamente
non mi interessa il valore assunto dal char ma dai singoli bit. La soluzione
che conosco ma piů lunga č fare una funzione che operi con una OR bit per
bit per ottenere il risultato voluto.

 OR bit per bit per ottenere il risultato voluto.
Innanzitutto ti conviene usare il tipo unsigned, giusto per evitare 
sorprese.
Il metodo diretto e' di utilizzare gli operatori di SHIFT ("<<" e ">>") 
abbinati all'operatore di AND e di OR. Ovviamente devi sempre tener 
presente il valore della macro CHAR_BIT (che con buona probabilita' varra' 
8, ma non puoi darlo per scontato) per essere sicuro di non scrivere mai 
oltre la dimensione del byte.
se vui controllare il terzo bit di un byte, partendo da sinistra, 
considerando il byte piu' a sinistra con il valore di 0, quello piu' a 
destra con 7 fai qualcosa del tipo:
BIT_CHECK(b, pos) ((1 >> (pos)) & (b) == 0 ? FALSE : TRUE)
L'altra soluzione e' di utilizzare un campo, ma li "perdi" il concetto di 
posizione e ti riferisci ai singoli campi con un nome (come se fosse una 
normale struttura).
Penso che la via piu' utilizzata sia di operare direttamente sui bit pero'.
-- 
Mox
"Trust the programmer."
"Don't prevent the programmer from doing what needs to be done."
"Keep the language small and simple."
"Provide only one way to do an operation."

 operi con una OR bit per bit per ottenere il risultato voluto.
Prima  di  tutto  dovresti  operare  su tipi  unsigned,  visto  che  gli
operatori  bitwise  del C  non  hanno  risultati definiti  su  quantita`
signed.
Per  non usare  gli operatori  bitwise puoi  usare i  bit fields  di una
struttura, in questo modo:
struct bits {
        unsigned int b0: 1;
        unsigned int b1: 1;
        unsigned int b2: 1;
        unsigned int b3: 1;
        unsigned int b4: 1;
        unsigned int b5: 1;
        unsigned int b6: 1;
        unsigned int b7: 1;
};
Ogni  campo e`  lungo  1 bit. Tuttavia  non  vi e`  la  garanzia che  la
struttura sia  lunga esattamente  8bit, perche` il  compilatore potrebbe
decidere di allinearla in modo diverso [1].
Per me la  soluzione migliore resta quella di usare  un unsigned char ed
usare gli operatori bitwise, magari con l'aiuto di macro:
#define set_bit(c, n) ( c |= (1 << n) )
#define test_bit(c, n) ( (c & (1 << n)) ? 1 : 0 )
unsigned char c;
set_bit(c, 1);
printf("bit 1: %d\n", test_bit(c, 1));
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
The trouble with computers is that they do what you tell them, 
not what you want.
D. Cohen

 decidere di allinearla in modo diverso [1].
Ops, mancava la nota ;)
[1] Per la cronaca il gcc3.2 fa la Cosa Giusta(C), la struttura grossa
esattamente 8 bit.
-- 
Home: 
http://kronoz.cjb.net
Ci sono due cose che l'uomo non puo` nascondere:
essere ubriaco ed essere innamorato.

grazie per la dritta cercherň di realizzarlo secondo i vostri consigli ma
non avendo esperienza penso che farň la classica cazzata di inesperienza
percui ricorrerň ancora alla vostra esperienza. per ora grazie, buon natale
e buon anno.

scusa la mia ignoranza in fatto di compilatori il gcc di chi è? se è free
dove lo trovo? ricordo male o è quello della borland? per ora essendo tutto
a scopo ludico uso il turboc penso versione 1.0 "dataci" in università
dicendoci che era free. Per il resto mi cambia qualcosa usare il gcc? Oltre
che magari ha dentro le librerie definite con i nuovi standard?

, 
min...@tiscalinet.it
 
says...

Io ritengo + utile lavorare con gli and 
ad esempio per settare il 3 bit e lascaire tutti gli altri uguali
X=(X and b11110111) + b0000100;
per resettarlo
X=(X and b11110111);
Lo so che non č C ma č per capirci meglio!!!
GRAZIE
<<SAX>>

 X=(X and b11110111) + b0000100;
perche' fare 2 operazioni, quando basta un solo OR?

 con i nuovi standard?
Cambia che il  gcc e` attivamente sviluppato, crea codice  a 32bit, gira
un sacco  di unices  e anche  sotto windows. E`  un gradino  (anche due)
sopra il turboC.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Runtime error 6D at f000:a12f : user incompetente

grazie per le preziose info sul compilatore che ora sto scaricando...
p.s.: ho fatto un po' fatica a trovare quello giusto...

 #define test_bit(c, n) ( (c & (1 << n)) ? 1 : 0 )
-per lo shift come prima
-l'and serve per tirar fuori il valore del bit presente in c (la variabile)
- ? 1 : 0  da i 2 possibili risultati, ma come funziona?


cmq ho provato a compilare e vedere cosa esce e non mi stampa niente a
monitor. i define vanno,come ho fatto, messi fuori dal corpo del programma
#include
#define
int main()
{
corpo
}
?

 - luca preziati :

http://www.gnu.org
è software libero, e la borland non c'entra nulla.
Ciao,
-- 
oOO()             |Nicholas Wieland|
/ _/              |nicholas_wieland|
|/ [ Step on the ]|    @
yahoo.it
   |
\_)[  right foot ]|________________|

scusa se ti rompo per il compilatore ma ho scaricato un file di circa 25 Mb
che ho decrompresso e arrivavo a un totale di circa 110 mb ma il compilatore
li dentro non l'ho trovato. Potresti dirmi che cosa ci devo fare? devo
compilare qualcosa? grazie

uso una or in generale perchè il valore di partenza di X è 0

> #define test_bit(c, n) ( (c & (1 << n)) ? 1 : 0 )
Prendi sempre 1, lo shifti a sinistra di n posizioni e ottieni la tua 
maschera. Metti tutto in AND. Visto che la maschera contiene tutti "0" 
tranne un unico "1", se e solo se il bit in posizione "n" di "c" varra' 1 
allora il risultato dell'espressione sara' diverso da 0.
In realta' e' superfluo ritornare 1 o 0 (anche se rende piu' esplicita 
l'operazione), gia' il valore dell'espressione sara' 0 se il bit non e' 
settato, diverso da 0 altrimenti... il che corrisponde a vero per come e' 
implementato il C :)
[1] In realta' tu non sai se lo shift sara' realmente a sinistra o a destra, 
    perche' non "sai" se il sistema usa little o big endian... a te pero' 
    non interessa perche' gli operatori di shift ne tengono conto in modo 
    trasparente. Sarebbe meglio parlare di:
    - "<<" come di shift verso le posizioni piu' significative e
    - ">>" come di shift verso le posizioni meno significative


 - ? 1 : 0  da i 2 possibili risultati, ma come funziona?
(exp1)?(exp2):(exp3) e` un operatore  condizionale. Vale exp2 se exp1 e`
vera, vale exp3 altrimenti. Nel test_bit faccio  un and bit a bit tra la
maschera  e la  variabile. Se il  bit considerato  e` a  1 l'espressione
sara`  vera (in  C vero  significa  != 0)  e quindi  test_bit varra`  1,
altrimenti varra` 0.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"La teoria e` quando sappiamo come funzionano le cose ma non funzionano.
 La pratica e` quando le cose funzionano ma non sappiamo perche`.
 Abbiamo unito la teoria e la pratica: le cose non funzionano piu` e non
 sappiamo il perche`." -- A. Einstein

 ha scritto nel messaggio
news:au4frb$p4q$1...@lacerta.tiscalinet.it...

Io utilizzo questo sistema:
struct S_bit_c{                             /* Struttura per bit in char */
             unsigned char B7:1;
             unsigned char B6:1;
             unsigned char B5:1;
             unsigned char B4:1;
             unsigned char B3:1;
             unsigned char B2:1;
             unsigned char B1:1;
             unsigned char B0:1;
            };
union SCHAR{                                /* Definizion unione per poter
manipolare il dato sia come byte che bit */
         unsigned char BYTE;
         struct S_bit_c BIT;
        };
int main(void)
{
  unsigned char Variabile_char
 (*(struct S_bit_c *)&Variabile_char).Bx = 0;     /* Pone il bit x di
Variabile_char a 0 */
 (*(struct S_bit_c *)&Variabile_char).Bx = 1;     /* Pone il bit x di
Variabile_char a 1 */
/* La cosa piu' bella succede con il codice seguente */
 (*(struct S_bit_c *)&Variabile_char).Bx =  (*(struct S_bit_c
*)&Variabile_char).By;
// Sposta il bit y nel bit x
// In assembler Hitachi diventa:
//    BLD      #y,@Variabile_char:8                ;Passa il valore del bit
y di Variabile_char in carry
//    BST      #x,@Variabile_char:8                ;Passa il vaore del carry
nel bit x di Variabile_char
// Con due istruzioni da 4 byte e' stato spostato il bit y nel bit x il
tutto in soli 6 cicli di clock
// Se poi Varibile_char fosse su un registro il tutto verrebbe eseguito in 2
soli cicli di clock
}
Secondo la mia esperienza, questo sistema, nonostante una certa complessita'
di comprensione del codice, ha il vantaggio che quasi tutti i compilatori
vanno ad utilizzare le istruzioni orientate ai bit eventualmente disponibili
nei micro in cui  il codice dovra' girare. Queste istruzioni normalmente
sono molto piu' compatte e veloci rispetto alle istruzioni di AND/OR in cui
il micro deve eseguire un load di un registro con un valore e poi eseguire
l'istruzione di AND la quale prevede anche il caricamento del suo argomento
ecc.ecc. con notevole dispendio di cicli macchina.
Sono consapevole che questo e' andare a cercare il pelo nell'uovo, ma in
certe applicazioni embedded questi trucchetti sono vitali.
Ciao
Giuseppe

 Variabile_char a 0 */
e usare le macro?
#define BYTE(X)  (*(struct S_bit_c *)&X)
#define BIT(X,Y) BYTE(X).B##Y
basta poi scrivere
 BIT(Variabile_char,1) = 0;
per ottenere 
 (*(struct S_bit_c *)&  Variabile_char  ) .B1  =0;

Paolo Podda ha scritto:

ops, noto ora che i nomi sono in conflitto con quelli dell'union: meglio 
se li metti in minuscolo

> Secondo la mia esperienza, questo sistema, nonostante una certa
complessita' di comprensione del codice,
non mi sembra molto complesso anzi più o meno in partenza mi aspettavo una
cosa del genere, una struct e operare sui bit uno a uno, poi mi sono trovato
una baraonda di informazioni e per ora non ho ancora trovato quella
funzionante, causa feste, ora proverò e poi al max ti martello con altre
domande.

Paolo Podda wrote:

Una piccola riflessione. Questa implementazione e' limitata: non puoi mai 
indicare il bit da modificare con una variabile.
<code>
    int i;
    char b;
    printf("inserisci un numero da 1 a 8\n"
    scanf("%d", %i);
</code>
Se tu fai:
    BIT(b, i) = 1;
Viene espansa come:
    (*(struct S_bit_c *)&  Variabile_char  ) .Bi  =0;
Cosa impossibile.
Potresti ovviarci con uno switch per controllare il valore di /i/ (quindi lo 
fai a runtime), ma non e' molto elegante ed e' ripetitivo.
Se tu "ragioni" a posizione (come facevamo negli esempi prima), gli 
operatori bit a bit sono piu' versatili.
Usare un campo di bit diventa piu' intuitivo quando ad ogni campo di 1 o 
piu' bit assegni un nome mnemonico, e tu operi poi solo su questo nome (per 
dirlo nei termini della frase precedente: "ragioni" in base al nome 
simbolico).
Esempio:
    struct s {
        unsigned char open: 1;
        unsigned char pippo:2;
        unsigned char pluto:1;
        unsigned char altro:4;
    };
Qui ha piu' senso (logicamente parlando) affidarsi al campo di bit.
Spero di esermi spiegato :)
Alla fine gli operatori bit a bit (con opportune macro) possono sempre 
equagliare i campi di bit, non e' sempre vero il contrario.


 (quindi lo fai a runtime), ma non e' molto elegante ed e' ripetitivo.
piccolo OT: in C++ si puo' fare in molti modi, dai template alle 
funzioni inline

 wrote:

non so che OS usi, ma suil mio Linux in <sys/param.h> ci sono le macro:
setbit(a,i)
clrbit(a,i)
isset(a,i)
isclr(a,i)
ciao,
costa

 funzioni inline
In C++ non si sarebbe mai posto il problema in questi termini. Io avrei 
usato un bit vector per risolvere tutto in modo elegante e scalabile.
Il C++ permette molte cose carine, pero' non lo conosco bene e non mi 
addentro in discussioni (che sarebbero pure OT).


 isclr(a,i)
$ cat /usr/include/sys/param.h
#define NBBY            CHAR_BIT
[SNIP]
/* Bit map related macros.  */
#define setbit(a,i)     ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
#define clrbit(a,i)     ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
#define isset(a,i)      ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
#define isclr(a,i)      (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)


 > Giuseppeł ha scritto:

In effetti questo era il passo successivo.
Per pigrizia e mancanza di tempo non ho proseguito :-))
Ciao
Giuseppe


In effetti poter indicare il bit con una variabile e' una questione che mi
sono posto, ma fino ad adesso non ho trovato un metodo per far capire al
compilatore di utilizzare le istruzioni orientate al bit.
Ho ovviato con piccole routine in assembler.
Forse e' solo una mancanza del compilatore che utilizzo che non riesce ad
ottimizzare bene il codice e quindi riconoscere che potrebbe ottimizzare
meglio il codice, ma utilizzando gli operatori bit a bit c'e' uno spreco
enorme (per me) di risorse.
Ciao
Giuseppe

 BIT_CHECK(b, pos) ((1 >> (pos)) & (b) == 0 ? FALSE : TRUE)
forse volevi scrivere:
BIT_CHECK(b, pos) (((1 << (pos)) & (b)) == 0 ? FALSE : TRUE)
shiftare a destra invece che a sinistra e' chiaramente una svista ma stai
attento all'operatore "&".
Ha una bassa priorita' (+ bassa dell'operatore "==")
Scrivere (1 << (pos)) & (b) == 0  equivale a scrivere (1 << (pos)) & ((b) ==
0).
Ciao,
Drago.

 BIT_CHECK(b, pos) (((1 << (pos)) & (b)) == 0 ? FALSE : TRUE)
Si e si: 2 stupi errori :( Grazie della correzione.
