tipos - ¿Cómo se declara una matriz de punteros de función constante en C?
punteros y vectores en c (5)
Necesito declarar una matriz de punteros a funciones como estas:
extern void function1(void);
extern void function2(void);
...
void (*MESSAGE_HANDLERS[])(void) = {
function1,
function2,
...
};
Sin embargo, quiero que la matriz se declare como constante, tanto los datos en la matriz como el puntero a los datos. Lamentablemente, no recuerdo dónde colocar la palabra clave (s) const.
Supongo que el puntero real, MESSAGE_HANDLERS en este caso, ya es constante porque se declara como una matriz. Por otro lado, ¿no podrían cambiar los punteros de función dentro de la matriz en tiempo de ejecución si se declara como se muestra?
Con VisualStudio 2008, obtengo:
void (* const MESSAGE_HANDLERS[])(void) = {
NULL,
NULL
};
int main ()
{
/* Gives error
''='' : left operand must be l-value
*/
MESSAGE_HANDLERS = NULL;
/* Gives error
l-value specifies const object
*/
MESSAGE_HANDLERS[0] = NULL;
}
cdecl
dice:
cdecl> explain void (* const foo[])(void)
declare foo as array of const pointer to function (void) returning void
¿Es lo que necesitas?
Hay una técnica para recordar cómo construir ese tipo. Primero intente leer los apuntadores a partir de su nombre y lea de derecha a izquierda.
¿Cómo declarar eso sin ayuda?
Arrays
T t[5];
es una matriz de 5 T. Para convertir a T en un tipo de función, escriba el tipo de retorno a la izquierda y los parámetros a la derecha:
void t[5](void);
sería una matriz de 5 funciones que vuelven vacías y no toman ningún parámetro . ¡Pero las funciones en sí mismas no se pueden rellenar en matrices! Ellos no son objetos. Solo los punteros a ellos pueden.
Qué pasa
void * t[5](void);
Eso todavía está mal, ya que simplemente cambiaría el tipo de devolución para que sea un puntero al vacío. Tienes que usar paréntesis:
void (*t[5])(void);
y esto realmente funcionará t es una matriz de 5 punteros a funciones que vuelven vacías y no toman ningún parámetro .
¡Estupendo! ¿Qué tal una serie de indicadores para arras? Eso es muy similar. El tipo de elemento aparece a la izquierda y la dimensión a la derecha. De nuevo, se necesitan paréntesis porque, de lo contrario, la matriz se convertiría en una matriz multidimensional de punteros enteros:
int (*t[5])[3];
¡Eso es! Una matriz de 5 punteros a matrices de 3 int .
¿Qué hay de las funciones?
Lo que acabamos de aprender es cierto sobre las funciones también. Declaremos una función tomando un int que devuelve un puntero a otra función que no toma ningún parámetro y devuelve void:
void (*f(int))(void);
necesitamos paréntesis nuevamente por la misma razón que la anterior. Ahora podríamos llamarlo, y llamar a la función devuelta apuntada de nuevo.
f(10)();
Devolver un puntero a la función que devuelve otro puntero para funcionar
¿Qué hay de esto?
f(10)(true)(3.4);
? En otras palabras, ¿cómo se vería una función tomando int que devuelve un puntero a una función que toma bool devolviendo un puntero a una función que toma el doble y devuelve vacío ? La respuesta es que solo los anides:
void (*(*f(int))(bool))(double);
Podrías hacerlo infinitas veces. De hecho, también puede devolver un puntero a una matriz al igual que un puntero a una función:
int (*(*f(int))(bool))[3];
Esta es una función que toma int retornando un puntero a una función que toma bool devolviendo un puntero a una matriz de 3 int
¿Qué tiene que ver con const?
Ahora que lo anterior explica cómo crear tipos complejos de tipos fundamentales, puede poner const
en lugares donde ahora sabe a dónde pertenecen. Solo considera:
T c * c * c ... * c name;
La T
es el tipo básico al que terminamos apuntando al final. La c
significa const o no const. Por ejemplo
int const * const * name;
declarará que el nombre tiene el puntero de tipo a un puntero constante a una constante int . Puedes cambiar el name
, pero no puedes cambiar *name
, que sería de tipo
int const * const
y tampoco **name
, que sería de tipo
int const
Vamos a aplicar esto a un puntero de función de arriba:
void (* const t[5])(void);
De hecho, esto declararía que la matriz contiene punteros constantes. Entonces, después de crear (e inicializar) la matriz, los punteros son const, porque la const
apareció después de la estrella. Tenga en cuenta que no podemos poner un const
delante de la estrella en este caso, ya que no hay punteros a las funciones constantes . Las funciones simplemente no pueden ser const ya que eso no tendría sentido. Entonces el siguiente no es válido:
void (const * t[5])(void);
Conclusión
La forma C ++ y C de declarar funciones y matrices en realidad es realmente un poco confusa. Primero tiene que entenderlo, pero si lo entiende, puede escribir declaraciones de funciones muy compactas usando este.
En situaciones como esta, haga un typedef
para nombrar la firma de su función, eso lo hace mucho más simple:
typedef void MESSAGE_HANDLER(void);
con eso en su lugar, debería ser justo:
MESSAGE_HANDLER * const handlers[] = { function1, function2 };
Para obtener el contenido real de la matriz constante.
EDITAR : Se eliminó la parte del puntero del typedef
, esto realmente es mejor (vivir y aprender).
No estoy seguro de si esto funcionará en ''C''. funciona en ''C ++'':
Primero defina MESSAGE_HANDLERS como un tipo:
typedef void (*MESSAGE_HANDLER)();
Luego, use la definición de tipo para declarar su matriz como constante:
MESSAGE_HANDLER const handlers[] = {function1, function2};
El truco está en typedef
, si puedes hacer lo mismo semánticamente en ''C'', debería funcionar también.