Pergunta

Em C, não é um erro lançar ponteiros de e para void *.

Um grande obstáculo em portar para C ++ é a necessidade de lançar ponteiros ao retornar de funções que lidam com indicadores genéricos, como malloc, e funções declaradas em meu próprio código, como void *block_get(Blkno const blkno);.

Meu código, no entanto, deve ser compilado por c e Compiladores C ++ com sucesso. Se eu fornecer moldes explícitos em todos os lugares por causa do C ++, eles devem ser elencos no estilo C e eu posso estar mascarando bugs devido ao lançamento de tipos de não-pontet para e para os tipos de ponteiros de ambos os idiomas.

Meu erro de referência é o seguinte:

struct Cpfs *cpfs = calloc(1, sizeof(*cpfs));

que no MSVC produz:

Erro 2 Erro C2440: 'Inicializando': Não é possível converter de 'void *' para 'cpfs *' e: src cpfs cpfs.c 179

Evidentemente eu não posso usar new ou static_cast que eu naturalmente eu usaria se não estivesse mais usando C. Qual é a melhor maneira de fornecer a segurança do tipo máximo em torno void *Para cada idioma com verbosidade mínima?

Foi útil?

Solução

Talvez algo assim? (não testado, nenhum compilador disponível, não usando macros com muita frequência):

#ifdef __cplusplus
    #define pointer_cast(type, pointer) reinterpret_cast<type>(pointer)
#else
    #define pointer_cast(type, pointer) (type)(pointer)
#endif

Outras dicas

Eu sugeriria simplesmente usar moldes de estilo C ou envolver o elenco em uma macro que se expande para nada (em c) ou um static_cast em C ++.

Se o seu compilador suportar decltype(), você pode usar um pouco de macro mágica para evitar ter que repetir explicitamente o nome do tipo (e, graças a sizeof, o tamanho do elemento):

#ifdef __cplusplus
#define my_calloc(VAR, COUNT) \
    static_cast<decltype(VAR)>(std::calloc(COUNT, sizeof *VAR))
#else
#define my_calloc(VAR, COUNT) calloc(COUNT, sizeof *VAR)
#endif

Exemplo de uso:

#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif

struct Cpfs *cpfs = my_calloc(cpfs, 42);

A solução mais limpa provavelmente seria usar apenas um compilador C e vincular os arquivos de objeto, embora ...

Faça uma função de alocador de substituição que você possa definir de maneira diferente para as compilações C e C ++:- Algo assim em um arquivo de cabeçalho:

#ifdef __cplusplus
template<typename TypeT>
TypeT* MyAlloc(TypeT** pOut,size_t cb){
  *pOut = static_cast<TypeT*>(malloc(cb)); //aint c++ pretty.
  return *pOut;
}
#else
  extern void* MyAlloc(void** ppv, size_t cb);
#endif

Agora você tem, nas compilações C ++, uma função que pode inferir o tipo de coisa que está lidando e, em C, é uma função regular que retorna um vazio*.

O único problema é a necessidade de passar no ponteiro para alocar - o compilador C ++ não tentará deduzir um parâmetro de modelo com base apenas no tipo de retorno de uma função AFAIK. Então você poderia chamá-lo de forma agnosticamente assim:-

int *p;
if(MyAlloc(&p,sizeof(int)*n)){
  ...

A única solução que conheço é fazer elenco explícito:

struct Cpfs *cpfs = (Cpfs*)calloc(1, sizeof(*cpfs));

Aqui, ambos os compiladores estão satisfeitos. Além disso, lembre -se de que, para compiladores mais antigos, Malloc pode devolver o char*.

hth

Mario

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