Pagina 1 di 2

da double ** a const double **

Inviato: mer gen 16, 2008 17:36
da lamarozzo
Stavo compilando un mio programma e mi sono imbattuto in una caratteristica del C che non conoscevo (e chissà quante altre sono :lol: ).

Ho una variabile dichiarata come double** il cui contenuto vorrei assegnare ad una variabile che punta ad una variabile costante. La mia prima idea è stata

Codice: Seleziona tutto

int main()
{
   double **slacky;
   const double **slackware;
   slackware=slacky;
   return 0;   
}


Ma googlando un po' ho scoperto che si tratta di un errore previsto dallo standard per evitare altri problemi (quali la possibilità di aggirare la constness di una variabile).

In un forum C++ ho trovato che la soluzione al mio problema è la seguente:

Codice: Seleziona tutto

int main()
{
   double **slacky;
   const double * const* slackware;
   slackware=slacky;
   return 0;   
}


Effettivamente se compilo il suddetto programma con g++ tutto fila liscio. Usando gcc invece continua a darmi

warning: assignment from incompatible pointer type

Sapevo che il C non è esattamente un sottinsieme del C++ ma non pensavo di trovare questa differenza di comportamento.

Come faccio ad implementare correttamente la stessa cosa in C?

Re: da double ** a const double **

Inviato: mer gen 16, 2008 18:31
da Blizzard
ciao,

puoi postare la fonte da cui hai preso quel codice... o comunque spiegarmi come funziona???
non è che ci ho capito molto ad intuito :P

Re: da double ** a const double **

Inviato: mer gen 16, 2008 18:34
da Blizzard
comunque con un cast esplicito il warning va via... non so se ci possono essere futuri problemi.

Codice: Seleziona tutto

    int main()
    {
       double **slacky;
       const double **slackware;
       slackware=(const double**)slacky;
       return 0;   
    }


EDIT: ho letto dopo scusate :P cancellate tutto quello che dico sopra

Re: da double ** a const double **

Inviato: mer gen 16, 2008 19:07
da lamarozzo
Blizzard ha scritto:ciao,

puoi postare la fonte da cui hai preso quel codice... o comunque spiegarmi come funziona???


Ciao,
il codice che ho postato è solo un esempio ridotto ai minimi termini in cui si fa un cast implicito da un tipo ad un altro. Secondo gcc sono problematici sia double** -> const double** che double** -> const double* const*, mentre per g++ solo il primo rappresenta un problema (e difatti lo è perchè può generare situazioni potenzialmente pericolose: per un esempio vedi in fondo a questo link http://www.parashift.com/c++-faq-lite/c ... #faq-18.17 ).

Come dici giustamente tu con un cast esplicito il compilatore non segnala problemi: ma è giusto? Non vorrei che la cosa fosse compiler dependent e un giorno che sposto il programma su un'altra macchina mi esplode tutto.

Re: da double ** a const double **

Inviato: mer gen 16, 2008 19:29
da Blizzard
ciao

Come dici giustamente tu con un cast esplicito il compilatore non segnala problemi: ma è giusto? Non vorrei che la cosa fosse compiler dependent e un giorno che sposto il programma su un'altra macchina mi esplode tutto.

di solito il cast esplicito dovrebbe funzionare ovunque perchè è una forzatura totale. Pertanto IMHO (ma può darsi che moltissimi mi smentiranno) non dovresti avere problemi di compilazione su altri sistemi e compilatori.

Il fatto è che i cast contribuiscono a generare codice poco sicuro... magari l'utilizzo di tali sistemi può portare a errori nascosti.
Nel c++ la questione dovrebbe essere leggermente diversa. Molto è affidato ai cast impliciti e sul manuale di Lippman/Lajoie è fortemente consigliato lasciar fare quanto possibile ai cast impliciti. Per tutto il resto sono stati definiti "operatori" (non so se è corretto dirlo) di cast appositi const_cast static_cast ecc... proprio per evitare la forzatura totale dei tipi.
Penso comunque che il tuo caso sia da vedere bene... dato che entrano in gioco puntatori e punatori const.

Lascio pertanto la parola agli esperti :p

P.S.
prima mi riferivo al codice c++ che non ho capito come funziona la dichiarazione strana... o meglio inconsueta :D

Re: da double ** a const double **

Inviato: gio gen 17, 2008 13:34
da puzuma
se ho capito bene il problema mi sa che hai bisogno dell'operatore const_cast

Re: da double ** a const double **

Inviato: gio gen 17, 2008 13:59
da puzuma
puzuma ha scritto:se ho capito bene il problema mi sa che hai bisogno dell'operatore const_cast



infatti non ho capito il problema ... const_cast è un operatore di c++ non di c

Re: da double ** a const double **

Inviato: gio gen 17, 2008 17:07
da lamarozzo
Sì, mi servirebbe la soluzione per il C. Per il C++, come ho fatto vedere, il problema non si pone perchè il compilatore non lancia nessun warning. Magari la soluzione con il cast esplicito è quella giusta, ma non ne sono sicuro.

Re: da double ** a const double **

Inviato: gio gen 17, 2008 18:01
da Dani
Provato a vedere se comporta problemi l'uso di qualcosa simile a:

Codice: Seleziona tutto

int main()
{
   double **slacky;
   const double * const* slackware;
   slackware = (const double* const*) slacky;
   return 0;   
}


?

Re: da double ** a const double **

Inviato: gio gen 17, 2008 18:39
da lamarozzo
Effettivamente con il casto esplicito il compilatore non si lamenta. Vuol dire che sarà la soluzione giusta, anche se pensavo che il cast a const potesse essere fatto in maniera implicita.

Grazie.

Re: da double ** a const double **

Inviato: gio gen 17, 2008 18:58
da nuitari
ma sei sicuro di quello che hai scritto?
la dichiarazione di una variabile come const implica che il valore non deve variare nel corso dell'applicativo, successivamente alla dichiarazione. per cui, se dichiari in un qualsiasi modo "slackware" come const, il successivo assegnamento (slackware=..) è in ogni caso un errore.

Non è che volevi fare una cosa del genere?

Codice: Seleziona tutto

#include <stdio.h>

int main()
{
   double ** slacky;
   double ** const slackware = slacky;

   printf("slacky:%p slackware:%p\n", (void *)slacky, (void *)slackware);

   return 0;
}


I cast sono problematici nella misura in cui vengono usati per costringere il compilatore ad accettare quelli che a tutti gli effetti sono errori.

Re: da double ** a const double **

Inviato: gio gen 17, 2008 19:36
da lamarozzo
nuitari ha scritto:ma sei sicuro di quello che hai scritto?
la dichiarazione di una variabile come const implica che il valore non deve variare nel corso dell'applicativo, successivamente alla dichiarazione. per cui, se dichiari in un qualsiasi modo "slackware" come const, il successivo assegnamento (slackware=..) è in ogni caso un errore.


Il cast è voluto. Ho una variabile double** che punta ad una matrice bidimensionale e voglio passarla ad una funzione. Voglio permettere alla funzione di leggere la matrice ma non voglio assolutamente che possa modificarla. Quindi nella dichiarazione della funzione ci sarà qualcosa del tipo

Codice: Seleziona tutto

void dummy(const double* const* matrice);


mentre il main ha qualcosa del tipo

Codice: Seleziona tutto

double **matrice;
...
dummy(matrice);


Soltanto che così il compilatore segnala un warning dicendo che c'è un problema con la conversione. La cosa migliore che si può fare per bypassare il warning sembrerebbe essere l'utilizzo di un cast esplicito, e cioè:

Codice: Seleziona tutto

double **matrice;
...
dummy((const double* const*)matrice);


anche se è un po' bruttino.

Ovviamente mi piacerebbe sapere se ci sono altre soluzioni o se sto sbagliando.

Re: da double ** a const double **

Inviato: ven gen 18, 2008 22:26
da nuitari
puoi postare il codice nella sua interezza per favore? almeno la parte interessata, con la dichiarazione della matrice.

EDIT:

Credo di aver colto.
Il motivo per cui non è giusto effettuare un cast da (type **) a (const type **) è perchè si tratta di un operazione pericolosa.
Guarda questo codice d'esempio:

Codice: Seleziona tutto

class Foo {
 public:
   void modify();  // make some modify to the this object
 };
 
 int main()
 {
   const Foo x;
   Foo* p;
   const Foo** q = &p;  // q now points to p; this is (fortunately!) an error
   *q = &x;             // p now points to x
   p->modify();         // Ouch: modifies a const Foo!!
   ...
 }


Mi sembra chiaro no? La sintassi giusta ovviamente è (const type * const *).

Il C++ accetta questa forma, i compilatori C pur accettandola (in quanto comune) segnalata uno warning perchè secondo la specifica ANSI C89:

both operands are pointers to qualified or unqualified types versions
of compatible types, and the type pointed to by the left has all the
qualifiers as the type pointed to by the right
[...]
For two qualified types to be compatible, both shall have the identical
qualified versions of a compatible type


Per cui picche.
Mentre è possibile assegnare un "top-level qualifier" extra ai pointer che l'argomento puntato non ha, questo non è permesso per gli elementi interni.
Per cui ad esempio (const type *) = (type *) sarebbe permesso (ma non nella C90).

Re: da double ** a const double **

Inviato: lun gen 21, 2008 9:27
da lamarozzo
Grazie nuitari.
Mi era chiaro che il cast double** -> const double ** è vietato perchè pericoloso ma non avevo chiaro in cosa differisse lo standard C++ con quello del C per quanto riguarda invece il cast corretto, double** -> const double* const*. Ora cercherò di approfondire un po' le cose che hai scritto, se ho problemi ti faccio un fischio :-'

Re: da double ** a const double **

Inviato: lun gen 21, 2008 13:43
da nuitari
Sai cosa, il fatto è che const in C è un *paliativo*. Il C non offre un vero controllo sui dati, dato che lavora più che altro con la memoria. Basti vedere la discussione che c'è stata sugli array in un altro post..

Il const serve per fare *quel controllo in più*, ma non va ne abusato ne bisogna pensare di essere *salvi* una volta che lo si è usato. Lo ha detto pure Torvalds tra l'altro =) In C vale sempre la regola *devi sapere quel che stai facendo*.

In C++ invece il discorso è diverso. Gli oggetti const differiscono da i non cost in quanto a struttura, cambiano proprio i membri, per cui non è sempre corretto fare un cast da const a non const per via delle differenze intrinseche, non si tratta solo di una questione di *compilazione*.