Estou escrevendo uma função em que gostaria de aceitar 2 type
s de parâmetros.
- A
string
(caractere *) - A
structure
onde haverá n número de elementos.
E para conseguir isso, estou pensando em usar um simples void *
como tipo de parâmetro. Mas não sei como verificar se o parâmetro é de um tipo ou de outro, com segurança.
void*
pontos apontam.func_str
efunc_struct
e obter verificações de tipo em tempo de compilação._Generic
macro. Você também pode criar tipos de identificação automática, por exemplo, com uniões marcadas , o que significa que você não pode passar umachar *
sequência bruta . Tudo isso é provavelmente mais problemas do que vale a pena.Respostas:
A tradução de
void*
é"Caro compilador, este é um ponteiro, e não há informações adicionais para você sobre isso.".
Normalmente, o compilador conhece melhor que você (o programador), por causa das informações que ele obteve anteriormente e ainda se lembra e você pode ter esquecido.
Mas neste caso especial, você sabe melhor ou precisa saber melhor. Em todos os casos,
void*
as informações estão disponíveis de outra forma, mas apenas para o programador, que "sabe". O programador deve fornecer as informações ao compilador - ou melhor, ao programa em execução, porque a única vantagem de umvoid*
é que as informações podem mudar durante o tempo de execução.Normalmente, isso é feito fornecendo informações por meio de parâmetros adicionais para funções, às vezes via contexto, isto é, o programa "sabe" (por exemplo, para cada tipo possível, existe uma função separada, a função que for chamada implica o tipo).
Então no final
void*
, não contém as informações de tipo.Muitos programadores não entendem isso como "não preciso saber as informações de tipo".
Mas o oposto é verdadeiro, o uso de
void*
aumenta a responsabilidade do programador de acompanhar as informações de tipo e fornecê-las adequadamente ao programa / compilador.fonte
void*
função, converter para o tipo errado, desassinar os dados ... todos os tipos de comportamento indefinido serão invocados.void*
são preteridos para programação genérica, não há muitas situações em que você deve usá-las hoje em dia. Eles são perigosos porque levam à segurança do tipo inexistente. E, como você observou, você também perde as informações de tipo, o que significa que você teria que arrastar algunsenum
junto com ovoid*
.Em vez disso, você deve usar C11
_Generic
que pode verificar os tipos em tempo de compilação e adicionar segurança ao tipo. Exemplo:Lembre-se de fornecer informações qualificadas (
const
versões ) de todos os tipos que você deseja oferecer suporte.Se você deseja erros de compilador melhores quando o chamador passa o tipo errado, você pode adicionar uma declaração estática:
Se você tentar algo como,
int x; func(x);
receberá a mensagem do compilador"x: incorrect type"
.fonte