da double ** a const double **

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

da double ** a const double **

Messaggio 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?

Avatar utente
Blizzard
Master
Master
Messaggi: 1509
Iscritto il: mar 2 gen 2007, 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox
Contatta:

Re: da double ** a const double **

Messaggio 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

Avatar utente
Blizzard
Master
Master
Messaggi: 1509
Iscritto il: mar 2 gen 2007, 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox
Contatta:

Re: da double ** a const double **

Messaggio 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

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Re: da double ** a const double **

Messaggio 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.

Avatar utente
Blizzard
Master
Master
Messaggi: 1509
Iscritto il: mar 2 gen 2007, 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox
Contatta:

Re: da double ** a const double **

Messaggio 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

Avatar utente
puzuma
Linux 2.x
Linux 2.x
Messaggi: 482
Iscritto il: mar 4 lug 2006, 17:14
Nome Cognome: Stefano Salvador
Slackware: current
Kernel: 2.6.32.2
Desktop: KDE 4.4.0
Località: Udine
Contatta:

Re: da double ** a const double **

Messaggio da puzuma »

se ho capito bene il problema mi sa che hai bisogno dell'operatore const_cast
The quiet ones are the ones who change the world. The loud ones only take the credit.

Avatar utente
puzuma
Linux 2.x
Linux 2.x
Messaggi: 482
Iscritto il: mar 4 lug 2006, 17:14
Nome Cognome: Stefano Salvador
Slackware: current
Kernel: 2.6.32.2
Desktop: KDE 4.4.0
Località: Udine
Contatta:

Re: da double ** a const double **

Messaggio 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
The quiet ones are the ones who change the world. The loud ones only take the credit.

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Re: da double ** a const double **

Messaggio 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.

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: da double ** a const double **

Messaggio 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;   
}
?

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Re: da double ** a const double **

Messaggio 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.

Avatar utente
nuitari
Linux 3.x
Linux 3.x
Messaggi: 777
Iscritto il: dom 14 ott 2007, 12:51
Slackware: 12.0
Località: San Colombano al Lambro
Contatta:

Re: da double ** a const double **

Messaggio 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.

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Re: da double ** a const double **

Messaggio 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.

Avatar utente
nuitari
Linux 3.x
Linux 3.x
Messaggi: 777
Iscritto il: dom 14 ott 2007, 12:51
Slackware: 12.0
Località: San Colombano al Lambro
Contatta:

Re: da double ** a const double **

Messaggio 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).

Avatar utente
lamarozzo
Linux 3.x
Linux 3.x
Messaggi: 732
Iscritto il: gio 14 lug 2005, 0:00
Desktop: xfce
Distribuzione: archlinux
Località: Roma

Re: da double ** a const double **

Messaggio 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 :-'

Avatar utente
nuitari
Linux 3.x
Linux 3.x
Messaggi: 777
Iscritto il: dom 14 ott 2007, 12:51
Slackware: 12.0
Località: San Colombano al Lambro
Contatta:

Re: da double ** a const double **

Messaggio 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*.

Rispondi