Eu sei que esta função irá me retornar um inteiro que é a soma dos dois parâmetros na função valor_1 e valor_2.
Eu vi em um programa que continha uma implementação parecida como a do segundo exemplo acima que usei para ilustrar a situação que testemunhei do uso do void. Eu testei a função soma() e ela retorna a soma dos dois parâmetros mesmo tendo o void especificado como retorno ou seja vazio.
Isto me deixou confuso em relação ao uso do void, eu pensava que servia somente para dizer que uma função não vai ter retorno nenhum ou não irá receber nenhum parâmetro como este exemplo soma(void).
Afinal de contas qual é a finalidade deste comando em C? O uso do void* especificado como ponteiro pode retornar valores mesmo sendo void?
O retorno void significa ausência de retorno. Já um tipo void * significa um ponteiro genérico, um ponteiro de um tipo desconhecido ou não especificado, um ponteiro para qualquer coisa, um endereço de memória qualquer.
Eles aparecem bastante na linguagem C, embora nem sempre o programador os perceba. Por exemplo, a função malloc retorna um ponteiro do tipo void *:
Aqui, o retorno de malloc é do tipo void *. O cast para int * é necessário para que você diga ao verificador de tipos do compilador para considerar que o valor retornado (que o compilador vai saber ser void *) deve ser considerado como sendo um int *. Neste caso, você recebe um ponteiro de tipo desconhecido e depois diz para o compilador qual é o tipo. Uma prova disso, é que esse mesmo código pode ser escrito de outra forma equivalente, denunciando o void *:
O void * também pode aparecer como um parâmetro, tal como na função free. A função free pode receber qualquer tipo de ponteiro, não importando qual é o tipo exato do objeto que é apontado. Por causa disso o tipo do seu parâmetro também é void *.
Outras funções também usam ou produzem ponteiros do tipo void *, em especial aquelas que trabalham com coisas na memória sem querer saber exatamente que coisas são essas, e sim apenas que se trata de alguma região na memória. Exemplo de funções como essa são a fread, fwrite, memset, entre muitas outras.
+1. Apenas um detalhe: não é uma boa prática fazer cast do retorno do malloc em C, apesar de ser obrigatório em C++. Uma boa argumentação aqui (em inglês): stackoverflow.com/a/605858/1796236 – Pablo Almeida 9/11/15 às 15:22
O void * estritamente significa um ponteiro para nada. Mas ele é melhor interpretado como ponteiro para qualquer coisa. Ou seja, esta é uma forma de generalizar um tipo, de deixar de especificar o tipo.
Quando o usa significa que você pode trabalhar com qualquer tipo de dado ali. Ele simplesmente aponta para um endereço de memória e é problema do programador que receberá isto saber tratar de forma adequada e provavelmente fazer um cast para o tipo desejado, de forma compatível com o que tem lá. Obviamente tragédias podem acontecer se tentar acessar de forma inadequada. Chama-se indireção.
É preciso cuidado quando usa ele porque perde uma das vantagens do C. É uma forma de criar dinamismo em uma linguagem estaticamente tipada. Também é uma forma de polimorfismo.