2012-11-01 9 views
9

Ho una struttura che contiene alcuni puntatori. Voglio che il valore di questi non sia modificabile. Ma semplicemente scrivere const infront non rende i membri della struct immutabilicorrettezza costante per le strutture con i puntatori

typedef struct{ 
    int *x; 
    int *y; 
}point; 

void get(const point *p,int x, int y){ 
    p->x[0]=x;//<- this should not be allowed 
    p->y[0]=y;//<- this should not be allowed 
} 

Qualcuno può indicarmi la giusta direzione.

EDIT:

Quindi sembrerebbe che non esiste un modo semplice di utilizzare il prototipo di funzione per dire che tutto ciò che appartiene alla struct dovrebbe essere immodificabile

+4

Cosa vuoi immodificabile? Il puntatore a 'int's? Quindi 'const int * x;' significa che non puoi modificare il valore puntato attraverso quel puntatore. I puntatori? Quindi 'int * const x;' vieta di modificare i puntatori. –

+0

Se int * x, è un array, quindi voglio che i valori all'interno di questo array non siano modificabili. – monkeyking

+0

Quindi hai bisogno di 'const int * x;' nella definizione della struct. Si noti che i valori nella matrice possono ancora essere modificati tramite altri puntatori (che possono richiamare un comportamento non definito, se 'x' punta a un elemento di' const int arr [3] = {15, 7, 3}; o così via) . –

risposta

2

di spiegare che cosa è necessario stabilire, quando si scrive

point str; 

point *p=&str; 

Qui p è un puntatore a str che è di tipo punto

Quando si dichiara come const, è significa che p è un puntatore costante. Questo non limita i puntatori che la struttura può contenere.

Se si desidera che il const ness da applicare all'interno della struttura, è necessario definire i puntatori all'interno della struttura anche come const

typedef struct{ 
    const int * x; 
    const int * y; 
}point; 

Ancora una volta a spingere a casa il mio punto di dichiarare il parametro come

void get(point * const p,int x, int y) 
    //Constant Pointer (*to prevent p from pointing to anything else*) 

    // AND 

    //Make the pointers inside point structure constant 
    //(*to prevent the int pointers x & y from pointing to anything else*) 

Se la struttura si sta puntando è anche l'uso const

 void get(const point * const p, int x, int y) 
    //Constant Pointer to constant structure 
+0

Se i miei membri della mia struct sono dichiarati const, come faccio a inserire valori in esso all'inizio del mio programma. – monkeyking

+0

Inserendo typecast in un puntatore non const. '(int *) (p-> x) = & qualunque'. Mentre potrebbe sembrare che sarebbe sconfiggere lo scopo del 'const'ness. Può essere molto utile su grandi progetti in cui si desidera assicurarsi che le modifiche a una struttura vengano eseguite solo in un luogo unico controllato. –

+0

Poiché il contenuto del puntatore è una costante, deve essere inizializzato durante la dichiarazione. –

1

Questo perché si modifica il contenuto della memoria puntato da un altro puntatore rispetto a p.

p punti su una struttura contenente 2 puntatori a int. Non si modifica la memoria a cui punta p ma un'altra area di memoria. Quindi il compilatore sta bene con quello.

 +----------+ 
p -> | x  | -> wherever 
     +----------+ 
     | y  | -> another place in memory 
     +----------+ 

Il const NESS od p non è ereditabile. Se avessi scritto p->a = array;, il compilatore si sarebbe lamentato. Il const è solo un contratto che dice che non cambierete la memoria attraverso quel puntatore.

3

Se ho compreso correttamente la tua domanda, ti piacerebbe ottenere la propagazione automatica della costanza dell'intero oggetto struct agli oggetti puntati da quei membri della struct. Cioè se l'oggetto struct non è const, gli array dovrebbero essere modificabili, mentre se l'oggetto struct è const, gli array non dovrebbero essere modificabili.

Se è così, quindi, sfortunatamente, non è ottenibile in linguaggio C.

In C++ è possibile forzare l'utente a utilizzare la funzione membro accessor per accedere ai membri dati (anziché accedere direttamente ai membri dati). Ma in C semplicemente non può essere fatto.

9

È possibile farlo senza fusione di caratteri mediante la definizione di un tipo di punto const e un tipo di punto mutevole, quindi utilizzare un sindacato trasparente:

typedef struct{ 
    const int * x; 
    const int * y; 
} const_point; 

typedef struct{ 
    int * x; 
    int * y; 
} mutable_point; 

typedef union __attribute__((__transparent_union__)) { 
    const_point cpoint; 
    mutable_point point; 
} point; 

Poi, si dichiara i parametri di funzione utilizzando sia il punto o il tipo const_point (mai il tipo mutable_point).

l'oggetto del tipo di punto verrà convertito in modo trasparente in un tipo const_point, ma non nel contrario. Ciò consente di avere un grado maggiore di sicurezza del tipo.

Vedi qui per un esempio in gcc: http://toves.freeshell.org/xueg/

Si noti che l'unione trasparente non è stata sostenuta nell'ultima versione di C++ ho controllato (non sono sicuro circa l'ultimo standard C++) in modo da può aspettare problemi di portabilità.

Può anche rendere il codice più difficile da leggere e mantenere, specialmente se si dispone di una struttura più complessa. ad esempio: potresti avere il tipo di punto in cui x o y è const oppure potresti dover incorporare la struttura puntiforme in un'altra struttura, ad es. rettangolo, per il quale potrebbe essere necessario definire più strutture per più tipi a seconda della loro costanza.

Tutto sommato, non sono sicuro che valga sempre la pena supplementare.

+0

Potrebbe valerne la pena se si desidera utilizzare i riferimenti in modo da poterlo istanziare con rvalue (dato che è possibile utilizzare rvalue con riferimenti costanti).Questo è probabilmente l'unico caso in cui sembra essere abbastanza utile per me. – meneldal

Problemi correlati