8
votes

Pourquoi 64 bits GCC a-t-il averti de convertir un const int à longtemps non signé INT lors de l'attribution d'un tableau?

J'ai un fichier test.cpp qui ressemble à ceci: xxx

la compilation en 64 bits GCC avec le drapeau -WSign-conversion produit l'avertissement : xxx

(ligne 2 est la ligne dans laquelle nouveau est appelé). Il me semble étrange que GCC devrait donner à cet avertissement sur l'allocation d'une matrice, mais les choses suivantes sont même étrangères:

  1. Remplacement de la ligne d'incrimination avec non signé Char * A = nouveau caractère non signé [(non signé Int) N]; ne se débarrasse pas de l'avertissement, ni n'utilise static_cast () .
  2. aucun avertissement n'est produit si f est défini avec la signature VOID F (t N) , où t est

    1. tout type d'entier non-const, signé ou non signé de toutes tailles, ou
    2. Un type d'entier 64 bits signé.

      Il produisit cependant des avertissements lorsque t est un type d'entier signé Const inférieur à 64 bits.

      Gardant à l'esprit que je suis sur une machine de 64 bits (Linux), pourquoi l'avertissement de conversion de la signature de la consension et la taille de n dans ce cas et pourquoi ne tape pas la coulée corrige le problème?

      Note 1: Je voulais tester cela sous un autre compilateur, mais le site COMEAU est en panne et je n'ai accès à aucun autre compilateurs, donc je ne peux pas dire s'il s'agit d'un comportement compatible standard ou d'un bogue GCC.

      note 2: test.cpp est un exemple minimal d'un problème d'un problème "Real" C ++ Dossier que j'ai dans lequel le meilleur moyen pour moi de me débarrasser de l'avertissement était d'entourer la ligne offensante avec: xxx


16 commentaires

Il vous avertit que si vous appelez f (-1) vous pourriez être surpris.


Vous ne pouvez pas affecter une matrice de taille négative, il est donc probablement de convertir n à une valeur non signée avant d'effectuer l'allocation. Changez votre paramètre en seulement non signé INT N et voyez si l'avertissement disparaît.


@Petebecker ouais, mais pourquoi ne pas avertir dans d'autres cas similaires?


@Petebecker - Cela n'explique pas pourquoi il ne produit aucun avertissement lorsque je change la signature de F à vide F (INT N).


Je soupçonne que c'est la conversion en Taille_T , qui est probablement un TypeDef pour Unsigned int .


@Ose - Vous demandez pourquoi le compilateur vous avertit de certaines erreurs courantes, mais pas toutes, moins courantes, de mauvais code?


C'est purement un avertissement "Knee Serk" - n'a rien à voir avec le nouveau op, mais simplement avec la conversion impliquée de la conversion "n" au "type de paramètre" du Nouveau op - Vous obtiendrez le même avertissement appelant une méthode avec le même type de parum. Et il s'agit d'avertissement que vous risquez de perdre la «signification» (de manière importante) sur la conversion signée -> non signée.


La raison pour laquelle il se produit uniquement pour const est probablement à voir avec les paramètres qui transparent des conventions de ce compilateur. Probablement la plupart des INTS sont élargis à 64 bits, la conversion int -> longue est vraiment 64 bits -> longue, mais apparemment des valeurs constantes sont traitées différemment. Ces choses peuvent devenir assez vissues.


@Hotlicks - c'est intéressant. Savez-vous s'il y a une documentation de ces conventions de transmission de paramètres GCC?


Je m'attendrais à ce que les statiques échouent parce que vous ne pouvez pas utiliser static_cast pour jeter la constance.


@Seose - pas un indice. Je suis sûr qu'il y a une documentation quelque part, mais cela peut être un texte très cryptique dans un endroit très obscur.


@Bopersson - Je demande si une explication technique intéressante est une explication technique intéressante pour laquelle le compilateur traite les cas superficiellement similaires que j'ai décrits différemment, pour vous assurer que je n'ai pas mal compris quelque chose de fondamental sur le système de type C ++.


@Adrianmccarthy - Oh oui, bon point. Je suis sur le point de partir en vacances, mais quand je reviendrai, je verrai si static_cast fonctionne. Je serai surpris si c'est cependant, étant donné que la coulée de style C ne fonctionne pas.


@Seose - Je crois que la raison est simplement que l'équipe du compilateur a connu ou reçu des rapports de bogues, certains problèmes de conversion. Ils ont ensuite décidé d'ajouter des avertissements pour des choses que les gens se contractent souvent.


@Seose: Le problème a été signalé avant plusieurs fois. Ceci est juste une bizarrerie du compilateur GCC, quelque chose que vous devez vivre. J'imaginerais que les auteurs du compilateur comprenaient maintenant inutile cet avertissement sont dans certains contextes et ont fait un effort délibéré pour le supprimer dans de tels contextes. Mais ils ne les ont pas tous obtenus, c'est pourquoi vous voyez cet avertissement apparaît si incohérent.


@Andreyt Merci, cela ressemble à un candidat à une réponse acceptable. Avez-vous un lien vers un rapport de bogue ou GCC Changelog pour le sauvegarder?


8 Réponses :


0
votes

const int est une valeur signée, vous jetez une valeur signée à la valeur non signée. Donc, le compilateur génère un avertissement qui, dans certains cas, cette conversion pourrait entraîner des calculs incorrects.


1 commentaires

int est également un type signé. Cependant, comme indiqué sur OP, si le paramètre est déclaré avec type int , il n'y a pas d'avertissement. C'est le const spécifiquement qui semble le déclencher. C'est le point clé de la question.



0
votes

Eh bien sa conversion pour vous, mais son avertissement vous avertissant que la conversion qu'il effectue changera le signe de la valeur qu'il change sinon vous pourriez automatiquement perdre de la valeur et les bogues pourraient resultir que vous soyez simplement Casting d'un INT vers un INT non signé Cela peut changer la valeur du signe normalement si je suis passé dans l'opérateur des limites de la matrice, il ne ferait pas l'avertissement comme si vous aimez cette

Essayez Turing of the Drapeau de conversion que vous avez sur et voyez s'il le fait toujours que le drapeau est ce qui cause l'avertissement parce que c'est la chose qui fait la conversion


0 commentaires

0
votes

Je suppose que cela devra faire avec la façon dont les littéraux entier sont manipulés: lorsque vous écrivez

int myArray[10];


0 commentaires

0
votes

Le TL; DR: Si cela représente la taille de quelque chose, faites-en un std ::ze_t .

Le problème est que le tableau new prend comme paramètre de taille une valeur de type std ::ze_t , qui est garanti par la norme comme un type intégré non signé, Comme en témoigne la plainte de la conversion du compilateur vers Unsigné longtemps Int . C'est là que la conversion non signée Signée a lieu et la solution correcte (IMO) de résoudre le problème est simplement de donner le paramètre n de fonction f type std ::ze_t . Cela supprime au moins l'avertissement avec GCC 4.6 pour X86_64 GNU / Linux.


2 commentaires

Cela n'explique pas pourquoi aucun avertissement n'est produit dans les conditions énumérées au point 2 de ma question. En outre, qu'est-ce que "TL; DR" signifie?


@Ose je ne suis pas sûr. Je pense que la meilleure explication est @ Andreyt's, que c'est juste un ennemi (éventuellement intentionnel) de l'analyse de type de GCC. "TL; DR" signifie trop longtemps; Ne [ou n'a pas] lu. "



0
votes

Le compilateur avertit, car le signe peut changer lors de la conversion d'une valeur non signée.

1. Remplacer la ligne d'incrimination avec un caractère non signé * A = nouveau caractère non signé [(long non signé INT) N]; ne se débarrasse pas de l'avertissement, ni n'utilise static_cast ().

Le problème de la conversion de signe persiste, vous venez de le rendre explicite. Je suppose que c'est que ce n'est toujours pas assez explicite pour que le compilateur vous croie. Il croit toujours que vous avez déclaré n a signé const int pour une raison!

2. Aucun avertissement n'est produit si F est défini avec la signature Void F (t N), où T est

1. Tout type d'entier non-const, signé ou non signé de toute taille

si n est non-const, il pourrait être le code entre le début de la fonction et la conversion, qui garantissait que N était positif, comme n = (long non signé INT) (n); . Il semble que le compilateur vous donne le profit du doute dans ce cas et donc ne prépare donc pas. Quand il est déclaré déclaré const, le compilateur sait certainement qu'il s'agit d'un int et avertit.

J'admets, mes explications ne ressemblent pas à quelque chose que g ++ ferait généralement.


0 commentaires

0
votes

Le problème réside dans la signature de votre fonction - le compilateur ferait une conversion implicite lorsque vous passez la littéral constant 4 à une fonction avec un argument correspondant déclaré comme const int .

Vous pouvez essayer de remplacer le type d'argument comme const non signé Int pour se débarrasser du message d'avertissement.


0 commentaires

1
votes

Je suis un peu floconneux sur les détails, mais il me semble que le problème est en réalité dans le signe l'extension em> (puisqueze_t est probablement un non signé longtemps sur votre système). Considérez le code suivant:

test.cpp: In function ?int main()?:
test.cpp:8:27: warning: conversion to ?long unsigned int? from ?const int? may change the sign of the result [-Wsign-conversion]
     char* bp = new char [b];


1 commentaires

Aucun de cela ne explique pourquoi le compilateur n'émet pas l'avertissement lorsque le paramètre Taille de la matrice n'est pas constitué. Par exemple. Ajout Char * NP = Nouveau Char [N]; à votre deuxième fragment de code ne produit pas d'avertissement supplémentaire.



0
votes

std ::ze_t est couramment utilisé pour l'indexation du tableau et le comptage de boucle. Les programmes qui utilisent d'autres types, tels que Unsigné Int, pour l'indexation du tableau peuvent échouer, par exemple. Systèmes 64 bits Lorsque l'index dépasse uint_max ou s'il s'appuie sur l'arithmétique modulaire 32 bits. Cliquez ici pour en savoir plus sur STD :: Taille_T et 64 bits Systems < / p>


1 commentaires

Merci pour votre contribution, mais cela ne répond pas non plus aux deux questions que j'ai posées. La meilleure réponse jusqu'à présent a été donnée par ant dans les commentaires ci-dessous la question.