Pergunta

Eu vi uma função cujo protótipo é:

int myfunc(void** ppt)

Esta função é chamada em um arquivo C como a = myfunc (mystruct ** var1);

onde mystruct é typedef para um de estrutura que temos.

Isso funciona sem quaisquer erros de compilação em MSVC6.0, Mas quando eu compilá-lo com algum outro compilador C, dá um erro no local onde esta função é chamada com mensagem de erro:

argumento do tipo mystruct ** é incompatível com parâmetro do tipo void **

O argumento de myfunc () é mantido como vazio ** porque parece ser uma espécie malloc genérica de função a ser chamada com vários tipos de estrutura variável para alocação de memória

  1. Existe algum tipo, como vazio ** permitido no padrão C / nenhum compiladores C?
  2. Como faço para corrigir isso? [I tentou lançar o argumento de chamada de função para mystruct**, mas não funcionou]

-AD

Foi útil?

Solução

void** é válido, mas, com base na sua mensagem de erro, você provavelmente terá que explicitamente lançar o argumento da seguinte forma:

mystruct **var1;
x = myfunc ((void**) var1);

Isso porque a função myfunc está esperando o tipo void**. Enquanto void* pode ser implicitamente convertido para qualquer outro ponteiro, que não é assim para o ponteiro duplo - você precisa lançá-lo explicitamente

.

Outras dicas

comp.lang.c FAQ aborda esta questão em detalhe na Pergunta 4.9 . Em resumo, eles dizem não é estritamente portátil para lançar uma arbitrária ponteiro-para-ponteiro para uma void **; eles vão a explicar que "código como este pode trabalhar e às vezes é recomendado, mas depende de todos os tipos de ponteiro que têm a mesma representação interna (que é comum, mas não universal)." Eles vão explicar que "qualquer valor void ** você joga com deve ser o endereço de um algum lugar valor void * real; moldes como (void **)&dp, embora possam fechar o compilador-se, são não portável (e não podem sequer fazer o que quiser)."

Assim, você pode seguramente / portably obter o comportamento desejado com um código como:

some_type *var1 = foo();
void *tmp_void_ptr = (void *)var1;
myfunc(&tmp_void_ptr);

Há uma razão para o compilador não pode converter automaticamente a partir mystruct** para void**.

Considere o seguinte código:

void stupid(struct mystruct **a, struct myotherstruct **b)
{
    void **x = (void **)a;
    *x = *b;
}

O compilador não vai reclamar sobre a conversão implícita de myotherstruct* para void* na linha *x = *b, mesmo que essa linha está tentando colocar um ponteiro para uma myotherstruct em um lugar onde apenas ponteiros para mystruct deve ser colocado.

O erro é de fato na linha anterior, o que está convertendo "um ponteiro para um lugar onde ponteiros para mystruct pode ser colocado" para "um ponteiro para um lugar onde ponteiros para qualquer pode ser colocar". Este é a razão não há nenhuma conversão implícita. Claro, quando você usa uma conversão explícita, o compilador assume que você sabe o que está fazendo.

Esta questão é um pouco confuso. Mas sim, void ** é certamente C legal e válido, e significa "ponteiro para ponteiro para void" como esperado.

Eu não tenho certeza sobre o seu exemplo de uma chamada, os argumentos ( "mystruct ** VAR1") não fazem sentido. Se var1 é do tipo mystruct **, a chamada deve apenas ler a = func(var1);, isso pode ser um erro de digitação.

Fundição deve funcionar, mas você precisa elenco para void **, que é o que os espera de função.

Como sujo como pode parecer:. Às vezes você não pode resolver um problema sem usar vazio **

Sim, void ** é perfeitamente aceitável e bastante útil em certas circunstâncias. Considere também que, dada a void **foo declaração e void *bar, o compilador vai saber o tamanho do objeto apontado por foo (ele aponta para um ponteiro, e todos os ponteiros são do mesmo tamanho, exceto em algumas plataformas antigas que você não precisa se preocupar) , mas não vai saber o tamanho do objeto apontado por bar (que poderia apontar para um objeto de qualquer tamanho). Você pode executar, portanto, com segurança ponteiro aritmética em ponteiros void ** mas não em ponteiros void *. Você deve lançá-los para outra coisa em primeiro lugar, como um char *. GCC irá permitir que você fingir que void * e char * são equivalentes, cada um apontando para um objeto um único byte em tamanho, mas isso não é padrão e não portável.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top