Newsgroup: it.comp.lang.c++
Titolo: Conversione stringa in long

Ciao a tutti,
volevo realizzare una funzione che effettuasse una conversione particolare.
In pratica, fornendo una stringa (es. "ABC") vorrei che restituisse il 
valore long 4276803 che è la rappresentazione decimale del valore 0x414243, 
ovvero quello derivante dall'affiancamento dei relativi codici ascii di ogni 
singolo carattere espressi in esadecimale.
Avevo pensato di scansire l'array di char effettuando poi uno shift di 8 bit 
ad ogni scansione, ma mi hanno detto che esiste un metodo più efficiente.
Quale potrebbe essere?
Grazie per le risposte.
Ciao. Stefano. 

 Quale potrebbe essere?
Esiste un modo più efficiente della manipolazione dei singoli bits?!?!
Scusa, se ti hanno detto che esiste un modo più efficiente, penso che
colui che abbia detto ciò, lo sappia questo metodo!!

un'idea (efficenza massima, non c'e` neanche una operazione!!):
union {
   char ABCD[4];
   unsigned int abcd;
} prova;
prova.ABCD[0] = '\0';
prova.ABCD[1] = 'A';
prova.ABCD[2] = 'B';
prova.ABCD[3] = 'C';
printf("%d\n", prova.abcd);
le union..... possono servire anche a questo!
occhio che se su una macchina intel (little endian) potresti ottenere 
risultati, diciamo, 'bizzarri'. Su una macchina big endian (come i buoni 
vecchi MOTOROLA, o le workstation Unix, basate su Alpha) tutto dovrebbe 
filare liscio.
Se ti stai chiedendo di che diavolo di indiani sto parlando, leggi 
questa pagina:
http://it.wikipedia.org/wiki/Ordine_dei_byte
ciao,
andrea



Forse: *(long*)"ABCD"
Ha la massima efficienza, in quanto non fa proprio niente, ma anche poca 
portabilita'.
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila

 un metodo più efficiente.
Chi l'ha detto. Bisogna vederlo per crederlo. Ogni volta che
qualcuno mi mostra uno, primo, non é giusto, e secondo, non é
più veloce. Hai già misurato il tuo, per vedere se é troppo
lente?
(Attenzione anche: non é garantita que 'A' vale 0x41; sui grossi
IBM, da essempio, non l'é. Bisogna guardare essatamente i
bisogni di portabilità.)
--
James Kanze                                           GABI Software
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, 
+33 (0)1 30 23 00 34

 Forse: *(long*)"ABCD"
vero! questa e` la soluzione piu` semplice. che sciocco a non pensarci.


 le union..... possono servire anche a questo!
Non, non possono servire a questo.


 ha scritto nel messaggio 
news:TveOg.22144$6Z1....@tornado.fastwebnet.it...


 fa proprio niente, ma anche poca portabilita'.
In fatti, non conosco sistemi dove funzionna. Sul Intel, non dà
il risultato voluto, e sul Sparc, fà un core dump (o non,
seguendo altre cose nel programma).
E in ogni caso vietato del linguaggio.


 Forse: *(long*)"ABCD"
Cioè
(long&)"ABCD"
Kiuhnm

 Non, non possono servire a questo.
ho detto "anche"...
andrea

 Primo, é rigorosemente vietato del linguaggio. 
scusa, quale parte del codice è vietata ? L'uso della printf ?
Voglio dire, la union è legale, legalissima.
Al massimo, e penso sia la fonte delle notevoli difformità di 
comportamento che hai segnalato, può essere vera o falsa la 
equivalenza implicita, data per scontata nella union, che :
4 * sizeof (char) = sizeof (unsigned int).
Questo ovviamente non è vero ad es, su una macchina a 64 bit 
(dove int è sostanzialmente un long a 8 byte e non a 4)
PEr quanto riguarda l'allineamento dei dati, valendo il più 
restrittivo della union, l'int, non penso ci siano problemi.
Una union più portabile avrebbe dovuto essere
 >> union {
 >>    char ABCD_etc [sizeof (unsigned int)];
 >>    unsigned int abcd;
 >> } prova;
 >
e il caricamento dei caratteri con un ciclo iterativo, allineati 
a destra o sinistra come meglio si intende (e badando di 
inizializzare con zeri i caratteri non usati dal testo).
Invece, giustamente fai notare anche l'altra debolezza, sulla 
non uniforme corrispondenza di codici numerici a caratteri asci 
su diverse macchine. Potrebbe anche esserci, ma su ciò non sono 
sicuro, qualche problema di implementazione del tipo plain char 
su sistemi che rappresentano i caratteri come w_char a livello 
di O.S. o di unicode, entrambi i casi di caratteri multibyte, e 
su cosa siano realmente le stringhe literal e i singoli 
caratteri literal tra apici. Se la mappa ragiona di default come 
w_char o unicode, con set estesi, è chiaro che il layout che ho 
scritto non funziona ancora nemmeno lui.
Non solo, difficilmente con unicode funzionerà mai, perchè i 
multibyte hanno spesso il byte esteso settato a valori non 
predeterminabili, e se anche fossero zeri, sarebbero zeri 
inframmezzati nel corpo dell'unsigned int, a spezzatino, e la 
conversione avrebbe esito disastroso, perchè presuppone che la 
parte significativa del codice ascii dovesse essere compattata 
insieme e non intercalata dai byte estesi.
Ciao
Soviet


 Kiuhnm

 Kiuhnm

 sostituzione della forma classica ?
Non sono a conoscenza di eventuali limitazioni, ma non si sa mai...
Kiuhnm

Non dovrebbe aggiungere niente di nuovo.
Ma che cacchio dici?!... ma la smetti di dire cretinate ?
Ora l'operatore '&' è syntactic sugar ? da quando ?

 >> } prova;
questo presume che sizeof(unsigned int) == sizeof(char[4]) e funziona
solo architetture con una certa endianess.
L'uso che viene fatto e' vietato dallo standard. In fine se uno vuole
fare cose non portabili di questo tipo almeno dovrebbe renderle visibili
usando i cast del C++, in questo caso reinterpret_cast.
Quando si fa il porting di un sistema si puo' cercare la stringa
"reinterpret_cast" e controllare che tutti i cast vadano bene anche
sulla nuova architettura/sistema.
Questo uso delle union e' troppo invisibile. Ad occhio non si capisce se
e' un uso legale di union (che non fa casting) o se e', come in questo
caso, un uso illegale di union.
Per concludere bisogna cercare di evitare qualunque forma di cast non
portabile, e quindi io scarterei a priori unions e reinterpret_cast.
Quindi concordo con James, la soluzione migliore e quella di usare shift
operators.
Tommaso
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 (long&)"ABCD"
No! In generale no...
*(long*)puntatore_a_stringa
equivale a:
(long&)*puntatore_a_stringa
e non a:
(long&)puntatore_a_stringa
per accorgertene usa il seguente esempio:
char my_string[] = "ABCD";
const char* p = my_string;
long a = *(long*)p;
long b = (long&)p;
long c = (long&)*p;
 
cout << a << endl;
cout << b << endl;
cout << c << endl;
long b = (long&)p; 
interpreta il valore del puntatore come un long
long c = (long&)*p;
interpreta il valore puntato (ed i successivi bytes) come un long.
Nel caso di 
(long&)my_string;
la passi liscia anche senza scrivere la forma piu' generale:
(long&)*my_string;
ma non e' il caso generale...
--> Andando sull'assurdo:
il tuo 
(long&)"ABCD"
non e' equivalente a:
*(long*)"ABCD"
come sostieni, ma piuttosto a qualche cosa *del tipo*:
*(long*)&"ABCD";
che si comporterebbe allo stesso modo e funzionerebbe per:
*(long*)&my_string;
ma non per:
*(long*)&p;
fine assurdo <-- 
Inoltre, se si usa questo tipo di cast bisognerebbe usare
reinterpret_cast che rende piu' chiara l'intenzione.
In sostanza:

Tra le due forme e' preferibile invece *(long*)"ABCD"; e cioe' indica
che le due forme siano equivalenti mentre non lo sono.
In generale castare a reference e' piu' potente ed espressivo, ma non
quando la cosa da castare e' gia' un puntatore:
float d = 3.4f;
int i = reinterpret_cast<int&>(d);
e' piu' espressivo di:
int i = *reinterpret_cast<int*>(&d);
la prima forma ha solo un &, la seconda ha un & e due *.
ma se abbiamo:
float *p = new float(3.4f);
int i = reinterpret_cast<int&>(*p);
non e' piu' espressivo di:
int i = *reinterpret_cast<int*>(p);
la prima forma ha un & ed un *, la seconda due *. Pari! (scusa la
spiegazione terra a terra).
Delle due la prima forma (cast to reference) sembra persino meno
naturale in questo caso.
Fatto questo esempio, preciso che castare un float in un int in questo
modo e' una cosa senza senso e non portabile, l'ho usato solo come
esempio e non come consiglio... (frase necessaria per evitare commenti
quali: quello che stai facendo non e' portabile... etc...)
Ed in fine, un cast di questo tipo va sicuramente evitato e si puo'
raggiungere il fine in un modo piu' pulito e portabile, vedi shift


 in sostituzione della forma classica ?
no. non e' affatto equivalente, per essere equivalente ed altrettanto
generale dovrebbe essere:
(long&)*"ABCD"
detto questo dovrebbe anche usare reinterpret cast per rendere chiara
l'intenzione pericolosa:
reinterpret_cast<long&>(*"ABCD")
e detto questo non dovrebbe esistere in quanto non portabile ed in
quanto esistono soluzioni portabili per raggiungere lo stesso fine.


 reinterpret_cast<long&>(*"ABCD")
nota che reinterpret_cast non puo' togliere constness, quindi in questo
caso che la stringa e' const:
reinterpret_cast<const long&>(*"ABCD")


 L'uso che viene fatto e' vietato dallo standard.
Bisogna però anche ammettere che il C++, talvolta, viene scelto perché 
non nasconde completamente l'hardware sottostante e quindi viene anche 
usato per scrivere codice non portabile.
In questi casi lo si usa praticamente come asm di alto livello.
Il C++ è anche questo, sebbene, a ragione, non su questo ng.
Chiaro comunque che deve esserci un netto vantaggio. Cioè si potrebbe 
violare lo standard per ottenere un incremento di prestazioni del 20%, 
non di certo per ottenerne uno di 0.00000001% (come spesso accade).
Kiuhnm

 non di certo per ottenerne uno di 0.00000001% (come spesso accade).
Capisco quello che vuoi dire...
In generale io non violo lo standard nemmeno per ottenere un incremento
di prestazioni del 300%... a meno che con un profiler non scopro che
aumentare le prestazioni di tale pezzo di codice del 300% non comporti
un aumento tangibile delle prestazioni del mio software.
In altre parole, puoi anche rendere un pezzo di codice 3 volte piu'
veloce, o anche 10 volte piu' veloce, ma se questo pezzo di codice viene
eseguito una volta sola o raramente e cmq quando viene eseguito impiega
poco tempo allora renderlo piu' veloce a scapito della portabilita' non
serve.


 questo non e` proprio possibile...
Scusa, ma hò mesurato. Possibile o non, c'è, almeno sul
processore e col compilatore che aveva. (Infatto, non mi hò
troppo soppreso. Connosco l'architectura Sparc, e sò un po comme
si fa il compilatore per genere il codice. Mà e anche certo che
puo essere diverso con un altro processore o un altro
compilatore.)
--
James Kanze (Gabi Software)              email: 
kanze...@neuf.fr


 (long&)*"ABCD"
Qui c'è una sottigliezza che non so se hai considerato.
Quando ho detto equivalente, mi riferivo all'operatore '&', non 
all'espressione in particolare.
Comunque, "ABCD" è un array, non un puntatore quindi, dereferenziandolo, 
forzi una conversione implicita a puntatore. Quindi *"ABCD" è 'A', non 
"ABCD" (ovvio, dirai...). Il cast successivo agisce quindi su 'A', però 
tutto fila relativamente liscio perché si tratta di un reference che 
"usa" un indirizzo.
Quello che invece accade in (long&)"ABCD" è che l'/array/ "ABCD" viene 
reinterpretato. Non so però se anche '&' forzi la conversione a 
puntatore. Comunque bisogna anche ricordarsi che "ABCD" ha dimensione 5 
e non 4, quindi un cast a 'long' è assurdo.
Entrambe le espressioni sono assurde.
Kiuhnm

 interpreta il valore del puntatore come un long
Stai dimenticando il fatto della conversione implicita array-puntatore. 
Vedi l'altro post.
Kiuhnm

 Qui c'è una sottigliezza che non so se hai considerato.
Forse, considerando questo codice, capisci meglio cosa intendo dire:
int main()
{
	int l1 = sizeof "ABC";
	int l2 = sizeof *"ABC";
}
Kiuhnm

 Qui c'č una sottigliezza che non so se hai considerato.
credo di aver considerato tutto e considerato tutto continuo a pensarla
come espresso da me in questo ed inaltri post.
nel caso specifico tutto funziona (se sei fortunato come spiegato), ma
nel caso generale no:
char my_string[] = "ABCD";
const char* p = my_string;
long a = *(long*)p;
long b = (long&)p;
long c = (long&)*p;
 
cout << a << endl;
cout << b << endl;
cout << c << endl;
la forma (long&)*"ABCD" e' piu' generale e funziona anche con p.
La forma (long&)"ABCD" sfrutta il fatto che il nome di un array e di una
string literal decadano al puntatore al primo elemento e falliscono di
funzionare nel caso generale, ad esempio con p.


 wrote 

ok, siamo tornati alle elementari... grazie speravo dessi per scontato
che sapessi questa cosa ;-)
nonstante sizeof(*"ABC") == sizeof(char) e *"ABC" == 'A', tu sai anche
che &*"ABC" == "ABC".
Quindi castando a reference (long&) tutto funziona (e' come aggiungere
l'extra & in &*"ABC").
Nel tuo caso invece se non fai *"ABC" ma fai solo "ABC", castando a
reference, ottieni una cosa simile a un &"ABC" che per tua fortuna:
&"ABC" == "ABC".
Questo pero' non e' vero nel caso generale:
char *p;
...
&*p == p
ma
&p != p
quindi il tuo modo non e' generale.
fare cast a reference con *c-string funziona sia con array, che con
stirng literals che con puntatori a stringhe.
fare cast a reference con c-string (senza *) funziona solo con array e
string literals ma NON con in putatori a stringhe.
Quindi e' una forma che porta prima o poi ad errori.
In generale tutti i cast portani ad errori, anche il cast della forma
*c-stirng. Nemmeno questo andrebbe usato e nemmeno questo e' portabile.
L'unica differenza e' che nella forma *c-string hai la speranza funzioni
per puntatori a stringhe, con il tuo modo (senza *) hai la certezza che
non funzioni.


 > long b = (long&)xxxxx;
hai una forma che funziona(*) in tutti i casi, per array, per string
literal e per puntatore a striga.
La forma senza il de-reference invece e' certo che non funzioni per
puntatori a stringhe.
Tommaso
* = funziona date determinate caratteristiche sistema. Entrambe le
soluzioni non sono portabili.


 la forma (long&)*"ABCD" e' piu' generale e funziona anche con p.
No, *"ABCD" è 'A'. E' questa la forma che funziona anche se non 
dovrebbe, sfruttando il fatto che un reference sia dopo tutto sempre un 
puntatore.
Se non lo capisci, non so cosa farci. Pensala pure come vuoi.
Kiuhnm

 generale.
Invece lo è. Se la usi sui puntatori non è colpa mia.
Kiuhnm

 Pensala pure come vuoi.
Anche tu.


 che &*"ABC" == "ABC".
Non sono la stessa cosa.
La prima indica un puntatore al primo elemento di "ABC", mentre la 
seconda indica l'array "ABC".
Nella seconda parte, la conversione a puntatore non č avvenuta.
Anche typeid mostra la differenza:
#include <iostream>
#include <typeinfo.h>
using namespace std;
int main()
{
	cout << typeid( "ABCD" ).name() << endl;
	cout << typeid( &*"ABCD" ).name() << endl;
}
Kiuhnm

 Se la usi sui puntatori non è colpa mia.
il motivo per cui la uso anche sui puntatori e' semplice... 
Il thread chiedeva come convertire una stringa, ad esempio "ABCD", in un
long.
E' stata data una risposta non portabile e discutibile:
long val = *(long*)"ABCD";
ovviamente "ABCD" e' un esempio, se veramente servisse sapere solo il
valore di "ABCD" l'autore avrebbe scritto:
const long abcdVal = xxxxxx; // "ABCD" reinterpreted as long
dove xxxx e' il numero a cui "ABCD" corrisponde se reinterpretato come
long.
usare il cast ha solo senso se ti interessa fare una conversione
at-run-time di una stringa che sai solo at-run-time, altrimenti usi una
costante numerica che e' efficiente e portabile.
Quindi un esempio reale sarebbe:
long getStringReinterpretedAdLong(const char *pString)
{
   return *(long*)pString;
}
...
long val =  getStringReinterpretedAdLong("ABCD");
l'esempio discutibile postato funziona (date determinate circostanze)
anche in questo caso, un caso reale e non stupido dove la stringa si
conosce a priori e quindi tanto vale digitale direttamente il valore a
mano!
Sostituendo la forma originale con la tua forma:
long getStringReinterpretedAdLong(const char *pString)
{
   return (long&)pString;
}
...
long val =  getStringReinterpretedAdLong("ABCD");
Il codice che prima poteva funzionare ora non funziona piu'.
sostituendolo in una forma realmente equivalente a quella postata
(quella da me descritta):
long getStringReinterpretedAdLong(const char *pString)
{
   return (long&)*pString;
}
...
long val =  getStringReinterpretedAdLong("ABCD");
Il codice funziona nuovamente (se prima funzionava) ed e' equivalente
alla versione postata inizialmente.
Per riassumere:
return (long&)pString;
funziona solo nel caso di string literal e array. 
return (long&)*pString;
funziona nei due casi prima citati ed anche nel caso di puntatore a
char.
Per questo dico che questa versione e' piu' generale ed e' l'unica che
e' equivalente a quella postata originariamente.
Nota che:
long getStringReinterpretedAdLong(const char pString[])
e' sempre un puntatore e la tua forma non funziona.
Detto questo e' male usare:
(long&)pString;
ma e' anche male usare:
(long&)*pString;
e
*(long*)pString;
meglio scegliere una soluzione portabile ed evitare queste cose.
Tommaso


 Il codice che prima poteva funzionare ora non funziona piu'.
Ma come fai ad affermare cose del genere???
E' chiaro che non funziona come intendi tu!!!
pString č un puntatore, non una stringa!!!
E' chiaro che č il suo valore a venire reinterpretato!
La funzione getString non accetta una stringa, ma il puntatore al primo 
elemento della stringa!!!
Sono due cose COMPLETAMENTE diverse.
Kiuhnm

 > che &*"ABC" == "ABC".
sia falsa. La affermazione e' giusta.
tutto cio' che ho detto rimane vero ed intaccato dal tuo discorso a mio
parere completamente fuori tema.


 Sono due cose COMPLETAMENTE diverse.
Lo so, ma scrivere codice che funziona solo nel caso si string literal e
di array di char mi pare poco generale e pericoloso.
In fine, la tua soluzione presentata come equivalente a quella postata
inizialmente non e' affatto equivalente in quanto non e' altrettanto
generale.


 (long&)*"ABCD"
hai ragione, non avevo controllato il livello di indirezione 
.... Mi sembra ugualmente migliore la scrittura con la reference.
ciao
Soviet
Ah, per quanto riguarda l'uso della union definito illegale, 
forse c'è stato un fraintendimento.
Io per illegale intendevo che non compila, o che viola qualche 
type check o simili (diciamo a livello di sintassi).
Invece qui la proibizione è più "stilistica", nel senso che 
compila e materialmente puoi farlo, ma non è garantito che 
funzioni (ed è vietato in tal senso).
Penso che usata con consapevolezza di quel che fai e di quali 
sono i suoi limiti, un simile comportamento possa essere 
ragionevole in certi contesti, specie se non pretendi di essere 
portabile e sviluppi per una architettura specifica di cui 
CONOSCI bene ogni dettaglio implementativo.
ciao
Soviet


 frase non sia giusta ed in particolare che:
però quel test non è del tutto oggettivo .... perlomeno non lo 
era con vecchi compilatori. Se ora la ridondanza dei literal 
DEVE essere mantenuta o DEVE essere eliminata, con comportamento 
in ogni caso univoco, allora la mia precisazione è diventata 
obsoleta
ciao
Soviet


 
volevo insomma dire che ogni literal è una sorta di variabile 
nascosta, e che due istanze uguali come dati dovrebbero essere 
distinguibili al compilatore stesso, dato che possono essere 
anche usate in modi diversi (ad es. sovrascrivendone una copia e 
non l'altra, e il compilatore dovrebbe garantire la consistenza 
dei literal non modificati a forza bruta ... credo)
riciao


 un momento .... 
"ABC" == "ABC"
Soviet Mario, hai ragione, questo test potrebbe fallire.
i due "ABC" potrebbero anche avere indirizzi diversi. 
ripensa a questa affermazione e le sue varianti come:
my_array == my_array


"Soviet_Mario" <Sov...@MIR.CCCP> wrote 
si, avevo perfettamente compreso quello che volevi dire ed e' una
giustissima osservazione.
il concetto di quello che volevo dire non cambia, rimane valido, ma
ovviamente il mio esempio no. Ripensalo con array e non con string
literal.
Grazie,


 > James Kanze                                           GABI Software


 asci su diverse macchine.
È un probleme diverso. Niete dice che si usa ASCII per i
caratteri, e infatti, certi compilatore (per i grossi IBM, da
essempio) usano ancore EBCDIC. Senza parlare degli caractteri
accentati, che variano anche fra un programma a l'altro sulla
stessa machina.
--
James Kanze (Gabi Software)              email: 
kanze...@neuf.fr


 ottenerne uno di 0.00000001% (come spesso accade).
In questo caso, infatti, ottene un decremento di prestazioni,
almeno sulla mia machina Sun.


 (long&)*"ABCD"
Credo di no. Non hò la mia copia della norma chi per verificare,
ma mi sembra que la conversione catena costante in puntatore non
si fà che si usa la catena come rvalue, e che non è il caso se è
operande di una conversione esplicita a una reference.
Anche, il risultato di *"ABCD" à 'A'.
In ogni caso, la costruzione mi sembra abbastanza stranno che
vale megliore evitarla.
(In fatti, se hò un long in cuì voglio mettere 0x41424344,
scriverò:
    long l = 0x41424344;
Mi sembra il più naturale. Pertroppo non è completamente chiaro
cosa voleva fare Stefano davero.)


 sembra ugualmente migliore la scrittura con la reference.
Prima di tutto, meglio aggiungere un const:
(const long&)"ABCD";
Tornando a noi, se adesso sei sicuro di aver controllato il livello 
d'indirezione, mi spieghi come mai, nel codice seguente, l1 contiene il 
contenuto di "ABC", mentre l2 il valore del puntatore p?
long l1 = (const long&)"ABC";
char* p = "ABC";
long l2 = (const long&)p;
Lo capisci adesso che "ABC" non è un puntatore, ma un array, cioè un 
oggetto?
L'aggiunta di '*' è concettualmente meno corretta oltre che ridondante.
Funziona solamente perché forza una conversione array-to-pointer di 
"ABC" da char[4] a char*. Dopo la conversione, ha luogo la 
dereferenziazione tramite '*'. Di conseguenza il reference non viene 
fatto puntare all'intero array, ma soltanto ad 'A'. Ma dato che 
l'indirizzo dell'array corrisponde a quello del suo primo elemento, 
tutto funziona ugualmente.
Te lo dimostro:
#include <iostream>
using namespace std;
typedef char (array)[5];
void f(array& a)
{
     cout << "array" << endl;
}
void f(char& a)
{
     cout << "char" << endl;
}
int main()
{
     char a[] = {1,2,3,4,5};
     cout << "a e' un "; f(a);
     cout << "*a e' un "; f(*a);
     cout << endl;
     cout << "Io, typeid, posso confermare che i due indirizzi sono 
uguali, ma indicano concettualmente cose diverse:" << endl;
     cout << "&a e' un " << typeid (&a).name() << endl;
     cout << "&*a e' un " << typeid (&*a).name() << endl;
}
Kiuhnm

 all'espressione in particolare.
Si, mà gli arrays in C++, almeno gli arrays typo C (perche in
generale in C++, un array si dichiara std::vector), son dei tipi
molti particolari. In questo caso, non sò proprio da testa se la
converione in puntatore si fà o non. (Si fà certamente col *.)
In ogni caso, utilisare il risultato de la conversione non
funzionna---sulla mia Sparc, da essempio, fà un core dump tre
volte su quattro. In generale, un long dev'essere alignato, ed
un array di char non.


 un array di char non.
Non ho mai avvallato quella scrittura.
Sono fin dall'inizio d'accordo con Carlo: quella forma č ALTAMENTE NON 
PORTABILE.
Kiuhnm

 d'accordo con Carlo: quella forma è ALTAMENTE NON PORTABILE.
In questo caso mi interessa meno la forma che il fondo. Anche se
faccio:
    char const* p = "ABCD" ;
    long l = *(long*)p ;
(che è, credo, l'intenzionne) non funzionna.
In generale, non è possibile prendere un array di sizeof(long)
char e di trattarlo comme long. Seguendo la norma, a un
comportamente indefinato, e nella realità, non funzionna.


 generale.
Potrei dire lo stesso della tua.
La mia funziona con qualsiasi oggetto, mentre la tua solo con i 
puntatori. Come la mettiamo adesso?
Comunque ho finalmente capito cosa volevi dire.
Anche quella di Carlo ha questo problema poiché forza la conversione da 
array a puntatore, quindi, sì, la tua è equivalente alla sua.
Ma io parlavo di equivalenza in senso più generale. E' per questo che è 
nata questa incomprensione.
Io volevo dire che tutto ciò che si può fare con '&' si può fare anche 
con '*' e viceversa.
Ci siamo capiti adesso?
Ne approfitto per dire che ritengo che '&' /sia/ syntactic sugar, 
sebbene è stato indispensabile introdurlo per evitare di dover scrivere
a = b = &c;
:)
Kiuhnm

 char e di trattarlo comme long.
Hai provato? ;)
Kiuhnm

 Kiuhnm

 Quindi anche se non è una cosa certa, è rischiosa (imho)
Soprattutto se si usa "ABCD" che ha lunghezza 5 anziché 4.
Kiuhnm

 Ci siamo capiti adesso?
credo di si.


 in modo diverso).
L'ho fatto solo perché insistevi sulla generalità. Non mi pare molto 
generale una forma che sfrutta la conversione array-to-pointer. Dal mio 
punto di vista, è più generale la mia.
Voglio dire che in generale *(*) equivale ad (&), tranne quando (a me 
pare un'eccezione) vi è la conversione atp. Come ho già detto, mi 
riferivo al caso generale, non a quella particolare espressione.
Ma tu indevi generale limitatamente alle stringhe, giusto?
Vabbe', comunque adesso ci siamo capiti.
Kiuhnm

 Voglio dire che in generale *(*) equivale ad (&), tranne quando (a me 
Adesso l'ho sfruttata anch'io la conversione :)
Avrei dovuto scrivere *(*)& <-> (&).
Kiuhnm

in modo diverso).
Non si tratta di un "puntatore a stringa": una stringa in C è una
sequenza di caratteri seguiti dal carattere nullo.  Data la sintassi e
la semantica del C, una stringa si puà quindi costruire o mediante
array di char o come puntatore a char.  In fase di inizializzazione di
un array di char, uno string literal NON decade nel puntatore al primo
elemento, così come NON decade se il nome dell'array è argomento di
sizeof o & (address-of).
Detto questo, l'espressione "puntatore a stringa" può essere
fraintesa, perché se la "stringa", in C, può essere rappresentata da
un puntatore a char o array di char, allora un "puntatore a stringa"
diventa un puntatore a puntatore a char o puntatore ad array di char.

 sizeof o & (address-of).
beh ovvio, non ho mai detto che cio' avenisse anche in questi casi
particolari.


particolari.
Non hai detto che non avvenisse, è diverso ;-)
Dire che "tutto è blu" non è la stessa cosa che dire: "tutto e blu,
meno le cose che non sono blu" ;-)
E, in ogni caso, è l'espressione "puntatore a stringa" ad invalidare
tutto il discorso.

 un array di char non.
E, per curiosita', la versione con la union? Teoricamente dovrebbe andare.

 Ciao. Stefano. 

Ops,
	era ntohl non htonl!
Giamba

 Hai provato? ;)
Si. Fà un core dump sul Sparc. Da un risultato diverso che
voluto sul PC sotto Linux (a volte aleatorio, se dimande
abbastanze ottimisazione a g++).
In più, è vietato dal linguaggio. A un comportemente indefinito,
che vuol dire ben troppo che funzionna nei tuoi tests, ma
provoca un core dump quando fà la dimonstrazione davanti il
cliente il più importante.
--
James Kanze                                           GABI Software


 dati.
Il probleme è più complicato. Infatti, la norma dice più o meno
che un "oggetto" non può essere accessato che comme il suo tipo,
o comme un array di char o di unsigned char. Si tu hai un
char[], il compilatore può non prendere in cosiderazione
espressioni di tipo long quando fà l'ottimisazione. G++ lo fà,
che vuol dire che in certi casi, non scrivere le date nel char[]
primo che era letto, perche non "vede" la lettura.
Come si dice in inglese: "if you lie to the compiler, the
compiler will punish you for it."
--
James Kanze                                           GABI Software


 cliente il più importante.
In realta' perche' funzioni e sia conforme e' necessario che l'array
sia allocato dinamicamente. Leggendo lo standard si ha l'impressione
che la garanzia fondamentale fornita dall'allocazione dinamica e'
quella dell'allineamento corretto, ma non so se sia sufficiente
garantire che l'array di caratteri sia allineato in modo adatto ad un
long per poter far funzionare anche la versione allocata
staticamente/automaticamente (tralasciando ovviamente i problemi di
endianness). In altre parole dato
#include <string.h>
#include <iostream>
#include <ostream>
union u {
  long l;
  char a[sizeof(long) + 1];
} uu;
int main() {
  strcpy(uu.a, "ABCD");
  long ll = *(long *)uu.a;
  std::cout << std::hex << ll << '\n';
}
non so se il codice e' valido anche se il valore di ll dipende
dall'implementazione o e' proprio comportamento indefinito.
Ciao,
Nicola

 dovrebbe andare.
Seguendo la norma, non. Mi son già servito di un compilatore
(sotto MS-DOS, col MS C versione 1.0) dove non andava.
Nella pratica, se ti servi di Sun CC o di g++, senza
ottimisazione, funzionna su un Sparc. Bisogna comunque vedere in
ogni caso cosa fà il compilatore. Con tutte le optioni di
ottimisazione.
--
James Kanze                                           GABI Software


 spesso è definita come macro).
Ed ancora
In ogni caso, l'ho misurato sul Sparc (senza il htonl, che non
fà niente sur Sparc), ed ho trovato che è meno veloce che la
soluzione coi <<.


 compiler will punish you for it."
beh, c'è il modo di mentirgli meglio, credo, eh he he
Ad es. se uno usa le union per fare cose sporche, si può 
istanziare un oggetto col modificatore VOLATILE, che è un modo 
di suggerire caldamente al compilatore di farsi i cavoli propri 
ed obbedire agli ordini senza presumere alcunchè.
Mi pare (non sono sicuro, eventualmente smentiscimi) che su 
oggetti di tipo "volatile" il compilatore non sia autorizzato a 
compiere alcun genere di ottimizzazione, perché in sostanza gli 
si dice che non può sapere tutto quel che accade a quella variabile.
A parte questo, non penso che usare un volatile comporti 
particolari overtime di accesso (al massimo, non risparmi niente 
quando hai il valore già in un registro, perché lo ricarica 
comunque, ma non è un prezzo esoso)
ciao
Soviet


 endianness). 
eh, non infatti. Se uno usa direttive tipo "pack structures" o 
sinonimi, per sprecare poco spazio, è possibilissimo che i char 
[] vengano messi dove c'è posto, anche a indirizzi dispari, e 
che letti come long creino problemi
CUT codice
ciao
Soviet

 Seguendo la norma, non.
Non capisco il perche', pero'.
Te lo chiedo perche' scrivendo codice per MMX ed SSE mi servo delle 
union abbastanza spesso ed in un modo simile a quello suggerito da Andrea.

 che letti come long creino problemi
Irrilevante. L'uso della union garantisce che l'array di caratteri e'
allineato come un long.
Ciao,
Nicola

 kanze wrote:
[...]

Beh, e' chiaro che se scrivi codice specifico per una piattaforma
quello che per lo standard e' comportamento indefinito per te e'
perfettamente definito da come si comporta in pratica la tua
piattaforma. Semmai diventa piu' importante avere specifiche chiare di
tale comportamento da parte del fornitore, per non incappare in
sorprese in caso di upgrade.
Ciao,
Nicola