2011-12-14 20 views
16

por favor considere el siguiente código:typedef const puntero WEIRDNESS

typedef struct Person* PersonRef; 
struct Person { 
    int age; 
}; 

const PersonRef person = NULL; 

void changePerson(PersonRef newPerson) { 
    person = newPerson; 
} 

Por alguna razón, el compilador se comlaining acerca de sólo lectura valor no asignable. Pero la palabra clave const no debe hacer que el puntero sea const. ¿Algunas ideas?

+2

"Pero la palabra clave const no debe hacer que el puntero sea const". ¿Huh? Respuesta corta: no use typedefs, solo están ahí para confundirlo. Recuérdalos hasta que los necesites. – wildplasser

+12

@wildplasser: "No use typedefs" no es un buen consejo. Tal vez "No ocultar punteros detrás de typedefs" es más apropiado ... –

+1

Me gustaría diferir. Es * un * buen consejo. Ocultar estructuras detrás de un typedef es tan confuso como ocultar punteros. Solo sirve para contaminar tu espacio mental. Incluso sin resaltar la sintaxis, leí "struct person * p" más fácil y rápido que "pPerson p". – wildplasser

Respuesta

33

Tenga en cuenta que

typedef int* intptr; 
const intptr x; 

no es lo mismo que:

const int* x; 

intptr es puntero a int. const intptr es puntero constante a int, no apunta a constante int.

entonces, después de un puntero typedef, no puedo hacer que const el contenido ya?

Hay algunas formas feas, como gcc de typeof macro:

typedef int* intptr; 
intptr dummy; 
const typeof(*dummy) *x; 

pero, como se ve, no tiene sentido si se conoce el tipo detrás de intptr.

+0

entonces, después de un puntero typedef, ¿ya no puedo hacerlo compatible con el contenido? – Johannes

5
const PersonRef person = NULL; 

es

struct Person*const person= NULL; 

por lo que se consting el puntero y no el objeto.

+0

entonces, después de un puntero typedef, ¿ya no puedo hacerlo compatible con el contenido? – Johannes

+1

sí, exactamente, uno de los motivos por los cuales 'typedef' de punteros suele ser una mala idea. –

0

que está recibiendo y error

error: assignment of read-only variable ‘person’ 

en la declaración

person = newPerson; 

, ya que han declarado como const persona por lo que su valor sólo es de sólo lectura .... valor const no se puede cambiar

si va a cambiar eso vatiable entonces ¿por qué lo está pidiendo const?

quitar la palabra clave const su voluntad código funciona bien

+0

sí, claro, me pregunto por qué el puntero es const y no el contenido al que apunta.eso es lo que esperaba ... – Johannes

1

Nunca se esconden detrás de los punteros typedefs, es muy, muy mala práctica y sólo creará errores.

Un error tan infame es que un tipo de puntero typedef: ed que se declara como const se tratará como un "puntero constante a datos no constantes", en lugar de "un puntero no constante a datos constantes" que es lo que uno intuitivamente espera Esto es lo que sucede en tu programa.


Solución:

typedef struct 
{ 
    int age; 
} Person; 

const Person* person = NULL; // non-constant pointer to constant Person 
3

Mientras que el problema ya está resuelto por las respuestas anteriores, no se pierda la razón por la ...

Así que tal vez como una regla de oro:

  1. El const siempre se refiere a que es símbolo predecesor.
  2. En caso de que no exista, es "intrincado" su token sucesor en su lugar.

Esta regla realmente puede ayudar a declarar un puntero a punteros const o algo igualmente limpio.

De todos modos, con esto en mente, se debe tener claro qué

struct Person *const person = NULL; 

declara un puntero const a una estructura mutable.

pensar en ello, sus typedef "grupos" la struct Person con el puntero símbolo *. Por lo tanto, para escribir

const PersonRef person = NULL; 

su compilador ve algo como esto (pseudo-código):

const [struct Person *]person = NULL; 

Como no hay nada que const 's la izquierda, que deklares el testigo al que esté bien struct Person * constante.

Bueno, creo que esta es la razón por la que no me gusta ocultar punteros por typedefs, mientras que me gustan los typedefs como tal. ¿Qué hay de escribir

typedef struct Person { ... } Person; 
const Person *person; /*< const person */ 
Person *const pointer; /*< const pointer to mutable person */ 

y debería ser bastante claro para los compiladores y los seres humanos, lo que estás haciendo.

Cuestiones relacionadas