Newsgroup: it.comp.lang.c
Titolo: Conversione strana da long a vettore di char

Vorrei convertire una long ad esempio 11092 in un vettore di char ,
ma non come si intende di solito cioè memorizzare in questo caso in un
vettore di 5 elementi :
[1][1][0][9][2] <- NO!
Vorrei che mi si convertano i bytes, perchè una long è formata da 4
Bytes quindi per memorizzarla
servirebbe un vettore di char di 4 elementi.
Quindi il mio vettore char conterrà nella prima posizione il primo
byte della long , nel secondo ecc....
fino alla quarta posizione che conterrà il quarto byte.
Si puo' fare una cosa del genere?
grazie

Si puo' fare una cosa del genere?
Puoi usare vari metodi:
(1) union:
union long_and_char {
    long x;
    unsigned char y[sizeof (long)]; /* meglio unsigned char */
};
(2) memcpy:
#include <string.h>
long var;
unsigned char vettore[sizeof var];
/* ... */
memcpy(vettore,&var,sizeof var);
/* ... */
(3) direttamente LSB in [0] (assumo CHAR_BIT == 8 e
nessun byte di spare):
#include <limits.h>
long var;
int i;
unsigned char vettore[sizeof var];
for (i=0; i<sizeof var; ++i) {
    vettore[i] = var & (1 << CHAR_BIT) - 1;
    var >>= CHAR_BIT;
}
In generale devi stare attento all'endianismo della macchina
con la quale lavori e alla possibilità di byte o bit di spare
(sempre possibili) per il tipo "long".
Nel metodo (3) hai una maggiore "portabilità" nel
senso che metti in ogni caso il byte LSB nel
primo elemento del vettore.
Puoi avere dei problemi se il numero è negativo quando
usi lo shift a destra.
In (1) e (2) sei invece soggetto la metodo
di memorizzazione del tipo long (big/little endian, o altri "endian").
Come hai visto dei stare attento ad un sacco di dettagli
se vuoi fare un codice "massimamente" portabile.
Nella maggioranza dei casi (3) funziona bene.
Se non ti interessa mettere il byte LSB nel posto [0] del
vettore puoi usare con tranquillità anche gli altri 2.
Essi vanno bene se vuoi copiare e/o usare la rappresentazione
in unsigned char. Forse è solo questo che volevi ...
--
Giorgio Silvestri
DSP/Embedded/Real Time OS   Software Engineer

 Può essere anche 1.
Una precisazione può  essere utile.
Su macchine in cui un byte è una sequenza di 8 bit, la lunghezza di un 
long *deve*  essere maggiore o uguale  di 4  byte se il compilatore 
rispetta lo standard.  Più  esattamente il massimo long deve essere 
maggiore o uguale di 2^31 - 1 ( 5.2.4.2.1 ). La possibilità  che 
sizeof(long)  sia 1  è  estremamente remota: potrebbe succedere solo su 
  un' implementazione in cui un byte corrispondesse ad almeno 32 bit.
Giorgio

   un' implementazione in cui un byte corrispondesse ad almeno 32 bit.
E' esattamente come hai detto infatti!
Io lavoro quotidianamente da circa 8 anni su una
macchina fatta così, non poi tanto remota come vedi.
Il sistema in questione è il seguente: DSP TI C32 (o famiglia C3X).
con
sizeof (char) = 1        (ovvio)
sizeof (short) = 1
sizeof (int) = 1
sizeof (long) = 1
sizeof (float) = 1
sizeof (double) = 1
sizeof (long double) = 2 (ma con 40 bit effettivi e non 64)
sizeof (void *) = 1
CHAR_BIT = 32     (come dicevi tu!)
La tua precisazione è naturalmente corretta.
Inoltre volevo solo enfatizzare che tale possibilità esiste.
In teoria non deve per forza esistere un'implementazione
che la realizza.
Comunque per l'OP la tua precisazione può
effettivamente essere utile per capire alcune cose ...


 usi lo shift a destra.
quali potrebbero essere questi problemi? (...qui sarebbe anche 
interessante sapere dall'OP qual e' lo scopo della conversione)
ps: ottimo post
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 }
...in particolare, vedo come parte problematica questa:
	(1 << CHAR_BIT)


"Cybertoldo" <cyber...@moc.liamg> ha scritto nel messaggio
news:emu9n8$ufi$2...@registered.motzarella.org...

Ti č sfuggita l'ipotesi fondamentale: CHAR_BIT == 8.
L'ho messa apposta.



Problemi grossi non ce ne sono.
Volevo solo enfatizzare che se si esegue lo shift a destra di un numero
negativo, il risultato è dipendente dall'implementazione.


 L'ho messa apposta.
Ops, scusa: mi era sfuggita la premessa.
Il problema e' pero' interessante, soprattutto abbinato all'esempio di 
quella "strana" architettura che ci hai mostrato.
Parlando sempre di un qualcosa di *maggiormente* portabile (o di 
riusabilita' del codice... comunque NON di portabilita' in senso 
assoluto) mi chiedo se non sarebbe quindi meglio modificare la linea:
	vettore[i] = var & ((1 << CHAR_BIT) - 1);
in:
	vettore[i] = var & (unsigned char)~0U;
oppure (togliendo proprio la maschera) in:
	vettore[i] = (unsigned char)var;
Le incognite di comportamento, se ho contato bene, rimarrebbero queste:
- la conversione di un tipo signed ('var') in uno unsigned, quando 'var' 
ha valore negativo
- lo shift a destra di 'var' (var >>= CHAR_BIT;), sempre in caso di 
valore negativo di 'var'
...ma entrambe, di solito, ben risolte dai compilatori.


 vettore[i] = (unsigned char)var;
O ancora più semplicemente:
vettore[i] = var;
tanto vettore[] è già "unsigned char".
La semantica però NON è la stessa.
Poniamo un valore negativo (es: -1L) di "var" e alle possibili
rappresentazioni:
- complemento a 2
- complemento a 1
- modulo e segno.
(A) vettore[i] = (unsigned char)-1L;
(B) vettore[i] = -1L & (unsigned char)~0U;
(C) vettore[i] = -1L & (1 << CHAR_BIT) - 1;
(A) non fornisce la rappresentazione di -1L a meno che
non si usi il complemento a 2 per i negativi.
(B) fornisce la rappresentazione di -1L ma
su una macchina simile al DSP che uso
-1L & (unsigned char)~0U diventa di tipo
"unsigned long" e quindi assume valore
ULONG_MAX (== UCHAR_MAX).
In questo caso funziona solo se
uso il complemento a 2.
(C) Con l'assunzione che ho fatto (CHAR_BIT = 8) fornisce
sempre la rappresentazione di -1L.
Vantaggi e svantaggi.
Visti i sistemi con cui ho avuto a che fare, mi
sembra che (A) e (B) possano funzionare per un
numero maggiore di essi.
(B) è comunque superiore ad (A).


 Visti i sistemi con cui ho avuto a che fare. ..
...e questo e' uno dei motivi per cui, quando mi capita l'occasione, mi 
piace romperti le tasche con domande di portabilita'.
Me ne verrebbe da fartene un'altra sull'argomento (legata alle 
rappresentazioni in 'complemento a uno' e 'modulo e segno')... ma per 
questa volta te la risparmio :)
Ciao e grazie



Alla prossima allora!
Comunque nessun problema, mi sembra che a tutti noi il C piace,
insieme a problemi di portabilità.
Per inciso comunque il DSP TI C3X usa il complemento a 2.
Comunque non mi pare di aver mai lavorato con sistemi che usino
un sistema diverso dal complemento a 2.
Per questo a volte faccio delle assunzioni (es: CHAR_BIT = 8).
Altrimenti non ne esco più vivo.
Quando faccio un post cerco sempre di avere in mente
una qualsiasi piattaforma. Per poter poi scrivere del codice
"massimamente portabile". Se possibile ...
O almeno confinare la "non" portabilità.
Certo, ora che ci penso, alcune mie vecchie librerie "casalinghe"
andrebbero rese più portabili ...
Mi metto al lavoro! Buone Feste A Tutti! :-)
