Eu tenho executado o seguinte código através de diferentes compiladores:
int main()
{
float **a;
void **b;
b = a;
}
Pelo que pude reunir, nãovoid **
é um ponteiro genérico, o que significa que qualquer conversão de outro ponteiro não deve compilar ou, pelo menos, emitir um aviso. No entanto, aqui estão meus resultados (todos feitos no Windows):
- gcc - lança um aviso, conforme o esperado.
- g ++ - Lança um erro, conforme o esperado (isso ocorre devido à digitação menos permissiva de C ++, certo?)
- MSVC (cl.exe) - Não envia nenhum aviso, mesmo com / Wall especificado.
Minha pergunta é: estou perdendo algo sobre a coisa toda e há algum motivo específico para o MSVC não produzir um aviso? MSVC faz produzir um aviso ao converter a partir void **
de float **
.
Outra observação: se eu substituir a = b
pela conversão explícita a = (void **)b
, nenhum dos compiladores emitirá um aviso. Eu pensei que deveria ser um elenco inválido. Por que não haveria avisos?
O motivo pelo qual estou fazendo essa pergunta é porque estava começando a aprender o CUDA e no Guia de programação oficial ( https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#device-memory ) o seguinte código pode ser encontrado:
// Allocate vectors in device memory
float* d_A;
cudaMalloc(&d_A, size);
que deve realizar uma conversão implícita para void **
para &d_A
, como o primeiro argumento de cudaMalloc
for do tipo void **
. Código semelhante pode ser encontrado em toda a documentação. Isso é apenas um trabalho malfeito no final da NVIDIA ou, novamente, estou perdendo alguma coisa? Como nvcc
usa o MSVC, o código é compilado sem avisos.
void**
não é um ponteiro genérico. Somentevoid*
é.(void**)
é um elenco explícito no estilo c. Ele diz ao compilador para não olhar de perto o que você está fazendo e confiar em você. É uma substituição explícita do sistema de segurança de tipo e os compiladores são obrigados a aceitar basicamente qualquer tipo de conversão. Moldes no estilo C devem ser evitados, pois são poderosos demais. Use conversões em C ++ como asstatic_cast
que reclamarão se você estiver tentando fazer algo que não faz sentido.Respostas:
Essa atribuição sem uma conversão é uma violação de restrição; portanto, um compilador compatível com padrão imprimirá um aviso ou erro. No entanto, o MSVC não é totalmente compatível com a implementação C.
Conversões de ponteiro via elenco são permitidas em algumas situações. O padrão C diz o seguinte na seção 6.3.2.3p7:
Assim, você pode converter entre os tipos de ponteiro, desde que não haja problemas de alinhamento e somente convertendo novamente (a menos que o destino seja a
char *
).Presumivelmente, essa função está desreferenciando o ponteiro fornecido e gravando o endereço de alguma memória alocada. Isso significaria que ele está tentando escrever para a
float *
como se fosse avoid *
. Não é o mesmo que a conversão típica de / para avoid *
. Estritamente falando, isso parece um comportamento indefinido, embora "funcione" porque os processadores x86 modernos (quando não estão no modo real) usam a mesma representação para todos os tipos de ponteiros.fonte
&d_A
não possui o tipo necessário?