web-dev-qa-db-fra.com

Comment résoudre: "transtypage en pointeur à partir d'un entier de taille différente" dans le code C?

Je supprime les avertissements gcc d'un code hérité.

Est-il possible de supprimer l'avertissement "cast to pointer from integer of different size" via le transtypage:

example:

some_struct *ptr = func()  // func() returns an integer.

Quelqu'un peut-il me guider pour résoudre ces avertissements gcc?

10
Sandeep Singh

Tout d'abord, si vous pouvez corriger func (êtes autorisé à modifier sa source), corrigez-le. Si ses calculs peuvent être effectués avec des pointeurs, faites-les avec des pointeurs et des pointeurs de retour. Parfois, il existe des raisons valables de travailler avec des adresses sous forme d'entiers (par exemple, pour traiter les problèmes d'alignement dans un code spécial). Dans ce cas, modifiez func pour utiliser le type uintptr_t (Défini dans stdint.h). Il est conçu pour traiter les pointeurs comme des entiers lorsque cela est nécessaire. (Il y a aussi intptr_t Si l'arithmétique signée est meilleure pour une raison quelconque, mais je trouve généralement que le uintptr_t Non signé est moins gênant.) De préférence, func devrait convertir le uintptr_t Vers un pointeur lors de son renvoi, donc le type de retour de func serait un pointeur (vers quelque chose, peut-être some_struct Ou void).

Si vous ne pouvez pas corriger func, vous pouvez utiliser des transtypages pour indiquer au compilateur que vous avez l'intention d'effectuer les conversions en cours. Cependant, ce message d'erreur particulier vous indique que vous ne convertissez pas simplement un entier en un pointeur, mais que vous convertissez un entier d'une taille (par exemple, quatre octets) en un pointeur d'une autre taille (par exemple, huit octets). Il est probable que ce code a été écrit à l'origine pour un système où le type entier renvoyé par func avait la même taille que le type de pointeur, mais vous compilez maintenant sur un système où le type de pointeur est plus grand ou moins que celui taille entière.

Dans ce cas, vous devez vous assurer que le calcul effectué par func fonctionne dans la nouvelle architecture. S'il ne renvoie qu'une valeur 32 bits, est-ce que cela conservera toujours la valeur correcte? Autrement dit, rien ne sera perdu par les 32 bits hauts manquants? Aucune adresse que func doit calculer ne dépasse jamais la valeur maximale du type entier qu'il utilise? Si func utilise des types entiers signés, considérez également le bit de signe.

Si vous vous êtes assuré que la valeur renvoyée par func est correcte, vous pouvez utiliser des transtypages explicites, tels que: some_struct *ptr = (some_struct *) (intptr_t) func();.

21
Eric Postpischil

Mon gcc ne donne pas l'avertissement que vous avez cité. Ce serait aussi étrange car il n'y a pas de cast dans votre code.

Je reçois l'avertissement

assignment makes pointer from integer without a cast

Notez la partie "sans plâtre". Ainsi, vous pouvez rendre gcc silencieux en castant (sans changer le comportement):

some_struct *ptr = (void*)func();

Ensuite, vous obtiendrez votre avertissement ("transtypé en pointeur à partir d'un entier de taille différente") si le type de retour de func ne convient pas aux adresses. Cela peut être réduit au silence en convertissant en outre func() en un type entier approprié, par ex. intptr_t:

some_struct *ptr = (void*)(intptr_t)func();

Tout cela sous l'hypothèse que vous voulez vraiment convertir l'entier de mauvaise taille en un pointeur. Probablement, retravailler le code est une meilleure idée.

6
undur_gongor

Il y a deux possibilités ici:

  1. func transforme un pointeur réel en un entier; il est ensuite utilisé comme pointeur.
  2. func renvoie un entier qui est stocké dans un pointeur; ptr est ensuite converti en entier et utilisé comme entier.

Dans le premier cas, la valeur de retour de func va perdre des informations , et potentiellement planter ou pire, si int est plus petit que la taille d'un pointeur de données, ce qu'il sera sur la plupart modèles de mémoire 64 bits (y compris Windows et Linux). Dans ce cas, vous devez changer le type de retour de func en intptr_t; voir tiliser intptr_t au lieu de void *? et Pourquoi/quand utiliser `intptr_t` pour le transtypage en C? .

Dans le second cas, c'est moins un problème, mais pour traiter les problèmes d'endianité, vous devez transtyper via intptr_t: some_struct *ptr = (some_struct *)(intptr_t)func(); et plus tard int value = (int)(intptr_t)ptr;. Voir Macros de conversion de type GLib pour une discussion du problème.

3
ecatmur