Como é que se declarar uma matriz de ponteiros de função constante em C?
-
22-07-2019 - |
Pergunta
Eu preciso declarar uma matriz de ponteiros para funções como assim:
extern void function1(void);
extern void function2(void);
...
void (*MESSAGE_HANDLERS[])(void) = {
function1,
function2,
...
};
No entanto, eu quero a matriz para ser declarado como constante - tanto os dados na matriz e o ponteiro para os dados. Infelizmente, não me lembro onde colocar a palavra-chave (s) const.
Estou assumindo o ponteiro real, MESSAGE_HANDLERS neste caso, já é constante porque ele é declarado como uma matriz. Por outro lado, não podia os ponteiros de função dentro da matriz ser alterado em tempo de execução se for declarada como mostrado?
Solução
Há uma técnica para lembrar como construir tal tipo. Primeiro tente ler ponteiros a partir de seu nome e lido da direita para a esquerda.
Como declarar essas coisas sem ajuda?
Arrays
T t[5];
é um array de 5 T . Para fazer T um tipo de função, você escreve o tipo de retorno à esquerda, e os parâmetros para a direita:
void t[5](void);
seria ser um array de 5 funções retornar void e tomando nenhum parâmetro . Mas a própria funções não podem ser recheadas em matrizes! Eles não são objetos. Somente ponteiros para eles pode.
E
void * t[5](void);
Isso ainda é errado, pois seria apenas mudar o tipo de retorno para ser um ponteiro para void. Você tem que parênteses uso:
void (*t[5])(void);
e isso vai realmente funcionar. t é um array de 5 ponteiros para funções retornar void e tomando nenhum parâmetro .
Great! E sobre uma matriz de ponteiros para arras? Isso é muito semelhante. O tipo de elemento aparece à esquerda, ea dimensão à direita. Mais uma vez, os parênteses são necessários porque caso contrário a matriz se tornaria uma matriz multidimensional de ponteiros inteiros:
int (*t[5])[3];
É isso aí! Um array de 5 ponteiros para matrizes de 3 int .
E sobre funções?
O que acabamos de aprender é verdade sobre funções também. Vamos declarar uma função de tomar um int que retorna um ponteiro para outra função tomando nenhum parâmetro e retornar void:
void (*f(int))(void);
precisamos parênteses novamente por ele mesmo motivo acima. Poderíamos agora chamá-lo, e chamar a função retornou apontado novamente.
f(10)();
Retornando um ponteiro para função retornando outro ponteiro para a função
O que sobre isso?
f(10)(true)(3.4);
? Em outras palavras, como é que um função de tomar int retornando um ponteiro para uma função de tomada bool retornando um ponteiro para uma função de tomar casal e retornar void se pareceria? A resposta é que você só ninho eles:
void (*(*f(int))(bool))(double);
Você poderia fazer vezes de modo infinitas. Na verdade, você também pode retornar um ponteiro para uma matriz assim como você pode um ponteiro para uma função:
int (*(*f(int))(bool))[3];
Esta é uma função de tomada int retornando um ponteiro para um bool função de tomada retornando um ponteiro para uma matriz de 3 int
O que isso tem a ver com const?
Agora que o acima explicado como construir tipos complexante de tipos fundamentais, você pode colocar const
em lugares onde você já sabe onde eles pertencem. Basta considerar:
T c * c * c ... * c name;
O T
é o tipo básico que acabam apontando para no final. O c
significa qualquer const ou não const. Por exemplo
int const * const * name;
declarará nome para ter o tipo ponteiro para um ponteiro constante para uma constante int . Você pode alterar name
, mas você não pode mudar *name
, o que seria do tipo
int const * const
e nem **name
, o que seria do tipo
int const
Vamos aplicar isto a um ponteiro de função do acima:
void (* const t[5])(void);
Este seria realmente declarar a matriz para conter ponteiros constantes. Assim, depois de criar (e inicializar) a matriz, o ponteiros são const, porque o const
apareceu depois de a estrela. Note-se que não podemos colocar um const
antes da estrela, neste caso, uma vez que não há ponteiros para funções constantes . Funções simplesmente não pode ser const como isso não faria sentido. Assim, o seguinte não é válido:
void (const * t[5])(void);
Conclusão
O C ++ e C forma de declarar funções e matrizes, na verdade, é na verdade um pouco confusa. Você tem que obter a sua cabeça em torno dela em primeiro lugar, mas se você entender isso, você pode escrever declarações de função muito compactas usá-lo.
Outras dicas
cdecl
diz:
cdecl> explain void (* const foo[])(void)
declare foo as array of const pointer to function (void) returning void
É o que você precisa?
Em situações como esta, fazer uma typedef
para nomear sua assinatura função, que o torna muito mais simples:
typedef void MESSAGE_HANDLER(void);
com isso no lugar, ele deve ser apenas:
MESSAGE_HANDLER * const handlers[] = { function1, function2 };
Para obter o conteúdo real da constante de matriz.
Editar :. Removeram parte ponteiro do typedef
, isso realmente é melhor (ao vivo e aprender)
Com o Visual Studio 2008, eu recebo:
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;
}
Eu não tenho certeza se isso vai funcionar em 'C'. ela não funciona em 'C ++':
-
Primeiro defina MESSAGE_HANDLERS como um tipo:
typedef void (*MESSAGE_HANDLER)();
-
Em seguida, use a definição do tipo de declarar sua matriz uma constante:
MESSAGE_HANDLER const handlers[] = {function1, function2};
O truque está na typedef
, se você pode fazer o mesmo semanticamente em 'C', ele deve funcionar também.