J'ai exécuté le code suivant via différents compilateurs:
int main()
{
float **a;
void **b;
b = a;
}
D'après ce que j'ai pu rassembler, il nevoid **
s'agit pas d' un pointeur générique, ce qui signifie que toute conversion à partir d'un autre pointeur ne devrait pas compiler ou au moins lancer un avertissement. Cependant, voici mes résultats (tous effectués sous Windows):
- gcc - Lance un avertissement, comme prévu.
- g ++ - Lance une erreur, comme prévu (cela est dû au typage moins permissif de C ++, non?)
- MSVC (cl.exe) - Ne lance aucun avertissement, même avec / Wall spécifié.
Ma question est: est-ce que je manque quelque chose sur le tout et y a-t-il une raison spécifique pour laquelle MSVC ne produit pas d'avertissement? MSVC fait produire un avertissement lors de la conversion à partir de void **
à float **
.
Autre chose à noter: si je remplace a = b
par la conversion explicite a = (void **)b
, aucun des compilateurs ne lance d'avertissement. Je pensais que ce devrait être un casting invalide, alors pourquoi n'y aurait-il pas d'avertissement?
La raison pour laquelle je pose cette question est parce que je commençais à apprendre CUDA et dans le guide de programmation officiel ( https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#device-memory ) le code suivant peut être trouvé:
// Allocate vectors in device memory
float* d_A;
cudaMalloc(&d_A, size);
qui devrait effectuer une conversion implicite en void **
for &d_A
, car le premier argument de cudaMalloc
est de type void **
. Un code similaire peut être trouvé dans toute la documentation. Est-ce juste un travail bâclé de la fin de NVIDIA ou est-ce que je manque encore une fois quelque chose? Depuis nvcc
utilise MSVC, le code compile sans avertissements.
void**
n'est pas un pointeur générique. Seulementvoid*
.(void**)
est une distribution de style c explicite. Il dit au compilateur de ne pas regarder de près ce que vous faites et de vous faire confiance. Il s'agit d'un remplacement explicite du type de système de sécurité et les compilateurs sont tenus d'accepter pratiquement n'importe quelle sorte de conversion. Les moulages de style C doivent être évités, ils sont beaucoup trop puissants. Utilisez des castings C ++ comme ceuxstatic_cast
qui se plaindront si vous essayez de faire quelque chose qui n'a pas de sens.Réponses:
Cette affectation sans transtypage est une violation de contrainte, donc un compilateur conforme standard affichera un avertissement ou une erreur. Cependant, MSVC n'est pas une implémentation C entièrement conforme.
Les conversions de pointeurs via un casting sont autorisées dans certaines situations. La norme C dit ce qui suit dans la section 6.3.2.3p7:
Vous pouvez donc convertir entre les types de pointeurs à condition qu'il n'y ait pas de problèmes d'alignement et que vous ne reconvertissiez que (sauf si la cible est a
char *
).Vraisemblablement, cette fonction déréférence le pointeur donné et écrit l'adresse d'une certaine mémoire allouée. Cela voudrait dire qu'il essaie d'écrire sur un
float *
comme s'il s'agissait d'unvoid *
. Ce n'est pas la même chose que la conversion typique de / vers avoid *
. À strictement parler, cela ressemble à un comportement indéfini, bien que cela "fonctionne" car les processeurs x86 modernes (lorsqu'ils ne sont pas en mode réel) utilisent la même représentation pour tous les types de pointeurs.la source
&d_A
n'ont pas le type requis?