53 votes

avertissement "déréférencement de type punned va enfreindre les règles de crénelage strict"

J'utilise un code où je lance un enum* int*. Quelque chose comme ceci:

enum foo { ... }
...
foo foobar;
int *pi = reinterpret_cast<int*>(&foobar);

Lors de la compilation du code g++ 4.1.2), j'obtiens le message d'avertissement suivant:

dereferencing type-punned pointer will break strict-aliasing rules

J'ai googlé ce message, et constaté qu'il ne se produit que lorsque la stricte aliasing optimisation est sur. J'ai les questions suivantes:

  • Si je laisse le code de cet avertissement, il va générer potentiellement mauvais code?
  • Est-il possible de contourner ce problème?
  • Si il n'y en a pas, est-il possible de désactiver stricte de l'aliasing à partir de l'intérieur du fichier source (parce que je ne veux pas le désactiver pour tous les fichiers source et je ne veux pas faire un autre Makefile règle pour ce fichier source)?

Et oui, j'ai réellement besoin de ce type de lissage.

57voto

moonshadow Points 28302

Dans l'ordre:

  • Oui. GCC supposent que les pointeurs ne peut pas alias. Par exemple, si vous affectez par le biais de l'un puis de le lire à partir de l'autre, GCC peut, comme l'optimisation, de la réorganiser les lire et à écrire - j'ai vu cela se produire dans le code de production, et il n'est pas agréable à déboguer.

  • Plusieurs. Vous pouvez utiliser un syndicat pour représenter la mémoire que vous avez besoin de réinterpréter. Vous pouvez utiliser un reinterpret_cast. Vous pourriez lancer via char * à l'endroit où vous réinterpréter la mémoire - char * sont définies comme étant en mesure de faire un alias de quoi que ce soit. Vous pouvez utiliser un type qui a __attribute__((__may_alias__)). Vous pouvez éteindre le repliement des hypothèses à l'échelle mondiale à l'aide de -fno-strict-aliasing.

  • __attribute__((__may_alias__)) sur le type utilisé est probablement le plus proche que vous pouvez obtenir à la désactivation de l'assomption pour une section particulière du code.

Pour votre exemple, notez que la taille d'un enum est mal définie; GCC utilise généralement le plus petit entier de taille qui peut être utilisé pour la représenter, afin de réinterpréter un pointeur vers un enum comme un entier pourrait vous laisser avec non initialisée octets de données dans l'entier résultant. Ne pas le faire. Pourquoi ne pas les jeter à une assez grande de type entier?

11voto

CashCow Points 18388

Mais pourquoi tu fais ça? Il cassera si sizeof (foo)! = Sizeof (int). Ce n’est pas parce qu’une énumération est comme un entier qu’elle est stockée comme telle.

Donc, oui, cela pourrait générer un "potentiellement" mauvais code.

11voto

Markus Lenger Points 119

Vous pouvez utiliser le code suivant pour convertir vos données:

 template<typename T, typename F>
struct alias_cast_t
{
    union
    {
        F raw;
        T data;
    };
};

template<typename T, typename F>
T alias_cast(F raw_data)
{
    alias_cast_t<T, F> ac;
    ac.raw = raw_data;
    return ac.data;
}
 

Exemple d'utilisation:

 unsigned int data = alias_cast<unsigned int>(raw_ptr);
 

5voto

icecrime Points 23650

Avez-vous examiné cette réponse ?

La règle de crénelage strict rend cette configuration illégale, deux types non liés ne peuvent pas pointer vers la même mémoire. Seul char * a ce privilège . Malheureusement, vous pouvez toujours coder de cette façon, peut-être obtenir des avertissements, mais compilez bien.

2voto

Let_Me_Be Points 16797

L'alias strict est une option du compilateur, vous devez donc le désactiver à partir du makefile.

Et oui, cela peut générer un code incorrect. Le compilateur supposera effectivement que foobar et pi ne sont pas liés ensemble, et supposera que *pi ne changera pas si foobar modifié.

Comme déjà mentionné, utilisez static_cast place (et pas de pointeurs).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X