Newsgroup: it.comp.lang.c++
Titolo: [neofita] Problema con l'operatore di indirizzo

Non capisco, il comportamento dell'operatore di indirizzo (&), nel
seguente codice :
 
=========================
 
#include <iostream>
 
using namespace std;
 
int main()
{
 
char carattere[3]="ab";
cout<<&carattere[0]<<endl;
return 0;
 
}
 
=========================
 
...peche', utilizzando l'operatore di indirizzo (&)  nell'istruzione:
 
cout<<&carattere[0]<<endl;
 
..NON mi viene restituito (come invece mi sarei aspettato)
*l'indirizzo di memoria del primo elemento dell'array*, ma ottengo
tutta la stringa di input:"ab".
 
Stranamente, scrivendo le stesse istruzioni, con un con *array di tipo
intero*, il problema NON si presenta: ottengo l'indirizzo di memoria
(espresso in numero esadecimale) del primo elemento dell'array.
 
Dove sbaglio?
 
Potete darmi un aiuto?
 
Utilizzo il s.o. WinVista e CodeBlocks con compilatore: mingw32-g+
+.exe.
 
Ciao e grazie milleee!
 
 
 
 
 
 

 
 
Essendo l'espressione &carattere[0] di tipo char*, cout giustamente lo stampa
come tutti i char*, ovvero come stringa.
Ti torna?
 
Ciao!


NO, NON mi torna per niete...:-(((.... io mi  aspettavo, con
l'utilizzo dell'operatore "&",  l'indirizzo di memoria della variabile
"carattere" in esadecimale!!!...e poi perche' restituisce "ab" quando
il primo elemento dell'array carattere[0]="a" ?
 
Perche' poi se utilizzo il tipo *intero* con le stesse istruzioni
ottengo (come mi aspetterei) invece l'indirizzo di memoria in
esadecimale?
 
Ciao e grazie mille!
 
 
 
 
 
 

 
 
Fai confusione tra dato e rappresentazione.
Un variabile ha un tipo e un valore, punto. Quando la usi, a seconda di come
la usi, scegli una rappresentazione adeguata.
 
Ciao!

 Un variabile ha un tipo e un valore, punto.
 
Meglio ancora, ogni espressione (perché vale anche per lvalues e rvalues) ha un tipo e un valore.


Purtroppo continuo a NON capire..:-(((....supponiamo di lavorare con
un tipo INTERO:
 
=========================
 
#include <iostream>
 
using namespace std;
 
int main()
 
 
 {
 
int arraynum[3]={0,1,2};
 
 cout<<&arraynum[0]<<endl;
 cout<<&arraynum[1]<<endl;
 cout<<&arraynum[2]<<endl;
 
return 0;
 
}
 
 
 
=========================
 
Con il predetto programma (utilizzando l'operatore &)  ottengo gli
indirizzi memoria dei tre elementi dell'array:
 
0x22fef4
0x22fef8
0x22fefc
 
 
.....perche' se dichiaro un' array di tipo CHAR NON
ottengo(utilizzando l'operatore &) gli indirizzi di memoria dei vari
elementi che compongono l'array come invece avviene se utilizzo il
tipo INTERO?
 
Ciao e grazie mille!
 


 
 
-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
 

 Dove sbaglio?
 
Il tipo dell'espressione "&carattere[0]" � lo stesso di "char*".
 
Siccome la funzione template non membro std::operator<<() viene 
sovraccaricata per poter stampare valori di diversi tipi, fra cui "const 
char*", il compilatore sceglie in maniera non ambigua la seguente versione:
 
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os, 
const char* s );
 
che si comporta stampando tutti i caratteri della stringa puntata da 
"&carattere[0]"
 
Per stampare l'indirizzo di memoria di "carattere[0]" puoi convertire 
"&carattere[0]" in "const void*".  In questo caso, fra le varie versioni 
sovraccaricate della funzione membro basic_ostream::operator<<(), il 
compilatore sceglier�:
 
basic_ostream& operator<<( const void* value );
 
Il seguente esempio pu� essere di aiuto:
 
#include <iostream>
#include <type_traits>
 
using namespace std;
 
int main() {
    char carattere[3] = "ab";
 
    // dimostriamo che &carattere[0] � lo stesso tipo di char*:
    static_assert(is_same<decltype(&carattere[0]), char*>::value, "ops!");
 
    // stampiamo quindi un oggetto di tipo char*
    cout << &carattere[0] << endl;
 
    // l'istruzione sopra � identica a:
    const char* p = &carattere[0];
    operator<<(cout, p) << endl;
 
    // per stampare l'indirizzo di memoria di carattere[0]:
    cout << static_cast<const void*>(&carattere[0]) << endl;
}
 

 tipo INTERO?
 
Cos� ottieni l'indirizzo:
 
#include <iostream>
 
 
int main()
{
    char carattere[3] = "ab";
 
    std::cout << int( &carattere[ 0 ] ) << std::endl;
 
    return 0;
}
 
Praticamente devi convertire il tipo di &carattere[ 0 ] in un int affinch� 
cout te lo visualizzi come tale.
 
EMG
 
--
EMAG Software Homepage:     
http://www.emagsoftware.it
 
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
 
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg
 
The EMG Music page:         
http://www.emagsoftware.it/emgmusic
 
 
 

 [...]
 
 
Ciao  Manlio

 const char* s );
 
La suddette indicazioni ho difficoltà a seguirle...:-((..purtroppo
sono ancora agli inizi e non ho ancora molta familiarita' con le
classi e la programmazione ad oggetti.
 
...cmq, ho notato che, con l'uso di string (classe string), il
problema NON si presenta:
 
================================
 
#include <iostream>
#include <string>
 
using namespace std;
 
int main()
 
 
 {
 
string arraycar[3]={"blu","rosso","verde"};
 
 cout<<&arraycar[0]<<endl;
 cout<<&arraycar[1]<<endl;
 cout<<&arraycar[2]<<endl;
 
return 0;
 
}
 
===============================
 
ed ottengo gli indirizzi di memoria dei tre lelementi dell'array:
 
0x22fef4
0x22fef8
0x22fefc
 
Come mai con "string" il problema NON si presenta??
 
Ciao e grazie mille!
 
 
 
 
 
 

 [...]
 
 
Ciao  Manlio

 cout te lo visualizzi come tale.
 
Attenzione, ciò che dici è completamente scorretto.
In C++ non è definita la conversione di un tipo puntatore a un tipo 
intero mediante un cast "stile C". Per di più risulterebbe scorretto 
anche in C++ mediante reinterpret_cast<> su tutte quelle architetture in 
cui un puntatore non può essere rappresentato da un intero. Solo C++11 
dispone di un tipo intero sufficientemente largo perchè 
reinterpret_cast<> non perda informazione nella conversione. Ma anche in 
quest'ultimo caso, poichè all'autore interessa stampare l'indirizzo di 
memoria di un oggetto, è consigliabile, in casi ambigui, una conversione 
a "const void*" tramite static_cast<>, perchè operator<<() è 
sovraccaricato volutamente per stampare indirizzi di memoria di oggetti 
di tale tipo.
 

 problema NON si presenta:
 
Per avere un'idea del perch� uno dei tuoi prossimi argomento di studio 
dovrebbe essere il sovraccaricamento delle funzioni. Tuttavia, viste le 
tue precedenti domande su questo newsgroup, ti riconsiglio vivamente di 
adottare un (buon) libro di testo e di non cercare di imparare il C++ 
(solo) per tentativi. Imparare il C++ con un approccio "bottom-up" � 
faticoso, forse inutile. Come ti era stato consigliato, lo Stroustrup � 
un ottimo libro da questo punto di vista, perch� riserva volutamente i 
primi tre o quattro capitoli a una presentazione generica di tutte le 
caratteristiche del linguaggio, per entrare nel dettaglio solo nei 
capitoli seguenti. Del resto, l'autore, che ha anche esperienza di 
insegnamento come professore, nota che quello � un approccio in genere 
pi� redditizio.
 

> Attenzione, ci� che dici � completamente scorretto.
 
S�, hai ragione, scusate. Sono molto arrugginito con il C++... :-(


Quindi sarebbe giusto cos�?
 
#include <iostream>
 
 
int main()
{
    char carattere[3] = "ab";
 
    std::cout << static_cast < void * >( &carattere[ 0 ] ) << std::endl;
 
    return 0;
}



 
 


 un ottimo libro da questo punto di vista,
 
Ho ordinato lo Stroustrup, nel frattempo, stavo anticipandomi alcuni
argomenti, leggendo gli appunti da questo sito:
 
http://appunti-programmazione.blogspot.it/2010/12/puntatori-e-stringhe.html
 
 
..a tal proposito, l'esempio che propone NON credo sia corretto:
 
 
l'istruzione
 
char* pChar = "ganja";
 
..NON restituisce 6 byte come allocazione di memoria, ma ottengo
sempre 4 byte,  indipendentemente dalla lunghezza della stringa
assegnata al puntatore pChar, cioe':
 
char* pChar = "ganja";
char* pChar = "ganjaganja";
char* pChar = "gan";
 
..con la funzione sizeof(pChar), ottengo sempre 4byte(32bit)....come
ha spiegato lo stesso autore degli appunti in un altro capitolo, il
puntatore, dovendo contenere un indirizzo di memoria, utilizzera' , in
base all'architettura del pc, SEMPRE 32bit o 64bit, indipendentemente
dal tipo assegnato al puntatore....spero di NON avere detto ca**te!:-
((.
 
Ciao e grazie mille per l'infinita disponibilità e competenza!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 [...]
 
 
Ciao  Manlio

 Ciao  Manlio


On 30 Mar, 00:16, Manlio Perillo <manlio_perill...@SPAMlibero.it>
wrote:

C'e' qualcosa che mi sfugge...se provo con:
 
================================
 
#include <iostream>
 
using namespace std;
 
int main()
 
{
 
char* pcar[6] ;
 
char car[6] ="12345";
 
*pcar=car;
 
cout<< sizeof(*pcar);
 
return 0;
 
}
 
 
=============================
 
 
avendo posto :
 
*pcar=car; // assegno a *pcar il *contenuto* dell' array car: "12345"
 
allora:
 
cout<< sizeof(*pcar);
 
 
NON dovrebbe restituirmi 6 byte?...ed invece ottengo sempre 4byte!!:-
((
 
Ciao e grazie mille!
 
 
 
 
 

 contenere qualsiasi puntatore ?
 
Direi si. std::size_t è di solito sufficiente, ma purtroppo non c'e'
garanzia nello standard. Forse l'unico tipo intero ad avere questa
garanzia, sebbene ancora NON standard prima di C++11, è unsigned long
long preso da C99 e supportato già da molti compilatori C++ 98/03, tipo
che viene usato apposta per il marshalling di puntatori su architetture
a 64-bit.
 

      std::cout << static_cast < void * >( &carattere[ 0 ] ) << std::endl;
 
Va bene nel caso specifico, visto che carattere[0] non è const. Ma in 
generale è meglio static_cast<const void*>, valido anche per variabili 
dichiarate costanti.
 

 dichiarate costanti.
 
Giusto, grazie.


 NON dovrebbe restituirmi 6 byte?
 
No, perch� pcar � un array di puntatori a carattere e quindi ogni suo 
elemento ha la dimensione a compile time di un puntatore.



 
 


 [...]
 
 
Ciao  Manlio


 
E' errato
Ti puo andare bene nel 99% dei casi
Il tipo per contenere qualsiasi pointer è void*
 
 
 
 

 Ciao  Manlio
 
 



si questo è pacifico, ma ci chiedevamo se esistesse un tipo 
plain integral capace a sufficienza per contenente un puntatore.
DI FATTO deve esistere, perché qualunque architettura tratta 
i puntatori negli stessi registri e nelle stesse celle di 
memoria degli altri dati integral.
A quanto pare il problema è che non necessariamente il 
linguaggio è tenuto ad "esporre" un intero grande a 
sufficienza anche se deve gestirlo dietro le quinte.
Come si è detto molto spesso il più ampio tipo integral è 
grande esattamente come un void *, ma senza garanzie 
scritte. E' una scelta.
In casi estremi si può anche aggirarla copiando memoria a 
bruta forza dentro una struttura senza padding o persino una 
union. Forse questa soluzione è peggio del problema :)


 Il tipo per contenere qualsiasi pointer è void*
 
Tranne puntatori a funzione (perchè in teoria, un sistema potrebbe usare 
dimensioni differenti per gli indirizzi del codice e dei dati).
 
In pratica, la maggioranza dei compilatori lo permette, ed è richiesto da 
alcuni strandard che estendono ISO C, come POSIX.
 
Se provi a compilare il seguente codice:
http://pastebin.com/Mth12iWz
 
 
con gcc -pendantic, ottieni il warning
 
ISO C forbids initialization between function pointer and ‘void *’
 
Tra l'altro, questo significa che in ISO C, non è possibile stampare un 
puntatore a funzione tramite printf, a meno di fare conversioni a mano:
http://stackoverflow.com/questions/2741683/how-to-format-a-function-
 
pointer
 
 
Non so l'I/O del C++ come si comporta, ma sono curioso.
 
 
 
Ciao  Manlio

 [...]
 
 
Ciao  Manlio

 Almeno questo vale in C.
Direi che vale *solo* in C, visto che i VLA non esistono in C++ e mi 
pare che sia l'unico caso in cui sia richiesta la valutazione a runtime 
dell'operatore sizeof.
 
Ciao.
 

On 30/03/2013 13:32, Manlio Perillo wrote:

Secondo lo standard C++ sizeof è un operatore che valuta l'espressione 
esclusivamente in tempo di compilazione. Inoltre, secondo lo standard 
C++ gli array non possono avere dimensione variabile, quindi l'esempio 
che hai indicato purtroppo non è portabile. Tuttavia, molti compilatori 
C++ estendono lo standard consentendo la valutazione della dimensione 
degli array in tempo di esecuzione, come in C. Fortunatamente, questi 
casi sono facilmente individuabili dal compilatore che può generare dei 
messaggi di avvertimento se richiesto.
 
 


Confermo, ed infatti lo standard C++ dice che nel caso l'operando sia una 
espressione, questa non viene valutata.
 
Invece, in C, il fatto o meno che l'operando ("size expression") venga 
valutato è un "unspecified behaviour".
 
 
Ciao  Manlio


Anche in C vale solo per C99, per cui non è assolutamente raro trovare
compilatori per piattaforme embedded che si aspettano per il sizeof solo
un'espressione calcolabile a compile-time.
Personalmente, a di là della discussione accademica, l'utilità pratica di
tutto questo mi sfugge: certo, è una feature in più del linguaggio, ma non
averla non cambia di molto l'espressività.
 
Ciao!

 
 
Sto studiando l'ISO C99, e ci sono certe feature di cui non immaginavo 
l'esistenza [1], e mi chiedo per quale use case siano state aggiunte.  Ma 
a queste domande dovrebbe rispondere il rationale.
 
 
[1] ad esempio:
    void f(double a[restricted static 3][5]);
 
    Si tratta sempre di VLA, ma non si limita alla possibilità di indicare
    la dimensione con un valore non costante.
 
 
Ciao  Manlio

 averla non cambia di molto l'espressivit�.
 
Non so se ho capito bene cosa vuoi dire, ma credo che l'espressivit�
centri poco. Si tratta di dover scegliere se scrivere codice
portabile o meno.
 
Questo, per esempio, bench� diffuso, non � codice C++ portabile, al 
contrario di quanto ci si possa aspettare:
 
    size_t f(size_t x) {
       return x+x;
    }
 
    char s[f(3)];
 
Inoltre, se provi a dichiarare s nel namespace globale, noterai che non 
puoi compilare il codice nemmeno in C99 (o in C++ con un'estensione 
dello standard fornita dal compilatore).
 
Quindi se proprio vogliamo parlare di espressivit�, solo C++11 risolve 
il problema superando di fatto anche la limitazione in C, ma obbedendo 
sempre al fatto che la funzioni ritorni un'espressione costante, ossia 
valutabile in tempo di compilazione:
 
    constexpr size_t f(size_t x) {
       return x+x;
    }
 
    char s[f(3)]; // ok, anche se s globale
 

     char s[f(3)]; // ok, anche se s globale
 
Si, ma non ha nulla a che fare con i VLA.
Questo è un normale array, dove la dimensione è nota a compile time.
 
 
Ciao  Manlio

 
http://en.wikipedia.org/wiki/Constant_folding
 
 
Continuiamo a parlare di C++, vero? Le ottimizzazioni non c'entrano 
*assolutamente niente*.
 
Puoi compilare quel semplice programmino con il massimo delle 
ottimizzazioni, ma se ordini al compilatore di aderire allo standard C++ 
perchè vuoi la garanzia che il tuo codice sia portabile, allora quello 
sopra non è C++ valido.
 
Per esempio, se compili quel programmino con g++ -Ofast (massimo livello 
di ottimizzazione) e con -pedantic-errors (forza errore in caso di NON 
aderenza allo standard), ottieni, appunto un errore:
 
error: ISO C++ forbids variable length array 's' [-Wvla]
char s[f()];
 
http://liveworkspace.org/code/292LBF$0
 
 

 
 
Beh, quando vorresti scrivere "un qualcosa" in una maniera ma sei costretto
ad usare una logica diversa perché il linguaggio non te lo permette allora
hai un limite espressivo.
Non è né bene né male, ogni linguaggio (anche l'italiano) ha i suoi limiti.
Di sicuro c'è che ci sono linguaggi dove gli array possono essere dichiarati
in quel modo, e infatti si dice comunemente che hanno un'espressività (per
questo caso) maggiore.
 
Quello che volevo dire è che trovare un'altra strada, come hai fatto notare,
non è per nulla difficile, per cui si tratta di lana caprina.
 
Ciao!

 [...]
 
 
Ciao  Manlio

 
 
In realtà non è così semplice: il compilatore dovrebbe anche sapere se la 
funzione è pura (ossia restituisce sempre lo stesso risultato se vengono 
passati gli stessi parametri).
 
 
Ciao  Manlio


Qualche proposta recente è stata fatta per avere i VLA's anche in C++:
 
http://open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3497.html
 
 
Potrebbero esserci delle alternative migliori come indicato nel 
documento e non è escluso che qualcosa vedrà la luce già nella prossima 
versione dello standard.
 

 versione dello standard.
 
Secondo me non servono, a meno che non si voglia aggiungerli per 
compatibilità con il C.  Anzi, secondo me è stato forse un errore 
aggiungerli al C.
 
Piuttosto, io preferirei maggiori addizioni per migliorare le 
ottimizzazioni che un compilatore è in grado di fare, come le già 
esistenti restrict (che mi sembra non ci sia ancora in C++), le regole 
più stringenti per l'aliasing e _Noreturn.  Ad esempio la possibilità di 
dichiarare una funzione come pura (il linguaggio D lo supporta).
 
 
Ciao  Manlio

     char s[f(3)]; // ok, anche se s globale
 
 
Strano che il codice equivalente che sfrutta una estensione del GCC non 
funzioni:
 
    __attribute__((const)) size_t f(size_t x)
    {
        return x + x;
    }
 
    char bar[f(3)];
 
 
Evidentemente non è equivalente?
 
Tra l'altro, leggendo un articolo riguardo constexpr, sembra che il 
compilatore, nell'esempio che hai postato, *potrebbe* generare un errore 
se non ha voglia di calcolare f(3) a compile time.  Confermi?
 
 
 
Ciao  Manlio
 
 
Ciao  Manlio

 
 
Come al solito cerco di fare la voce pratica del discorso - non me ne vogliate.
 
Continuo a non capire il problema.
Se la funzione è semplice si scrive:
char bar[4]; /* max 4 values */
se la funzione è complessa, ma costante:
char bar[27]; /* calculated as f(x)*log(g(h)) as specified in a.doc:2.1.3 */
Se il valore dipende da qualche variabile di compilazione, probabilmente già
sono presenti script M4 o simili che fanno ben di peggio, per cui si fa fare
a loro il tutto (magari chiamando un programmino helper che calcola il valore,
d'altronde, se è complesso, lo metteremo sotto unit-test, no?)
 
Per cui, veramente, rimango dell'idea che la presenza o l'assenza di tutta o
parta della feature che descrivete mi risulta indifferente..
 
Ciao!

 
 
In questo caso specifico, in effetti non interessa.
Ma più in generale, il calcolo di espressioni (e la chiamata di funzioni) 
a compile time, può portare a migliori prestazioni.
 
Ma qui il meglio lo da sempre Common Lisp, dove hai a disposizione 
l'intero compilatore e puoi fare quello che vuoi, tipo eseguire intere 
porzioni di codice a compile time.
 
 
 
Ciao  Manlio

 se non ha voglia di calcolare f(3) a compile time.  Confermi?
 
No, lo escludo: per l'esempio che avevo scritto, il compilatore non può
generare alcun errore e *deve* valutare f(3) in tempo di compilazione
perchè la dimensione di un array deve essere un'espressione costante. In
questo caso il compilatore è costretto a verificare che f(3) è
un'espressione costante e a valutarla: e così è, in quanto sono 
espressioni costanti sia "3" che f (che era stata appunto definita 
constexpr correttamente perchè "x + x" è a sua volta espressione costante).
 
Ci sono casi in cui il compilatore può decidere di NON valutare
l'espressione in tempo di compilazione, per esempio:
 
size_t n = f(3); // improbabile, ma è ammessa la valutazione in tempo
d'esecuzione
 
size_t n = 3;
f(n); // f(n) non è constexpr perchè n non lo è
 
al contrario, constexpr size_t n = f(3) obbliga f(3) a essere valutata
in tempo di compilazione.
 
In generale, funzioni constexpr sono comunque aperte alle ottimizzazioni
anche dove non sia richiesta da standard una valutazione in tempo di 
compilazione.
 
Per ulteriori dettagli vedi lo standard, sezione 5.19.
 

 [...]
 
 
Ciao  Manlio

 Non so quale sia la scelta migliore.
 
Credo sia opinione comune che è sempre meglio sfruttare le
caratteristiche proprie di un linguaggio piuttosto che qualche supporto
(magari nemmeno tanto equivalente) specifico di questo o quel
compilatore. Perchè, prima che efficiente, un programma deve essere,
ovviamente, semanticamente corretto: con constexpr sai come andare con
certezza incontro a tutte e due le esigenze; con l'hint puoi soddisfare
forse il primo punto, ma nulla si può dire sulla correttezza semantica:
il fatto che non potevi usare una funzione con l'hint per specificare la
dimensione di un array ne è la dimostrazione.
Ad ogni modo ormai a volte si può più nemmeno parlare di "estensioni"
del compilatore, visto che alcuni degli __attribute__ più utili di GCC
sono già parte di C++11, con qualche garanzia in più come dicevo.
 

 aggiungerli al C.
 
In C, devo dire, li ho trovati comodi. In C++ sono d'accordo, molto
spesso si fa meglio ad usare un vector.
 
-- 
-riko
http://www.enrico-franchi.org/
 
http://rik0-techtemple.blogspot.com/