Comment dois-je traiter avec “signé/non signé” incompatibilité de mises en garde (C4018)?
Je travaille avec beaucoup de code de calcul écrit en C++ avec la haute performance et faible surcharge de la mémoire à l'esprit. Il utilise des conteneurs STL (surtout vector
) beaucoup, et parcourt que les conteneurs presque dans chaque fonction.
L'itération du code ressemble à ceci:
for (int i = 0; i < things.size(); ++i)
{
//...
}
mais il produit de la signé/non signé incompatibilité avertissement (C4018 dans Visual Studio).
Remplacement int
avec certains unsigned
type est un problème parce que nous avons souvent l'utilisation d'OpenMP pragmas, et il faut le compteur à int
.
Je suis sur le point de supprimer les (centaines de) mises en garde, mais j'ai peur, j'ai perdu un peu de solution élégante à ce problème.
Sur les itérateurs. Je pense que les itérateurs sont grands lorsqu'il est appliqué dans les endroits appropriés. Le code que j'ai travaille avec la volonté de jamais changer d'accès aléatoire de conteneurs dans les list
ou quelque chose (donc itération avec int i
est déjà conteneur agnostique), et toujours besoin de l'index en cours. Et le code que vous avez besoin de type (itérateur lui-même et l'index) juste complique les choses et dissimule la simplicité du code sous-jacent.
- Pouvez-vous poster un exemple où le pragma OpenMP ne vous empêche à l'aide d'un type non signé? Selon ceci cela devrait fonctionner pour tout intergal type, pas seulement
int
. - Je crois que cette question est mieux pour stackoverflow.
int
etstd::vector<T>::size_type
peut aussi être différente de la taille ainsi que dans ce paramètre. Par exemple, sur un LLP64 système (comme Windows 64 bits),sizeof(int) == 4
maissizeof(std::vector<T>::size_type) == 8
.- double possible de acceptable correctif pour la majorité des signed/unsigned mises en garde?
- double possible de stackoverflow.com/questions/8188401/...
- Cochez cette suggestion visualstudio.uservoice.com/forums/121579-visual-studio-ide/...
Vous devez vous connecter pour publier un commentaire.
C'est dans votre
things.size()
type. Il n'est pasint
, maissize_t
(il existe en C++, en C), ce qui équivaut à une certaine "habitude" type non signé, c'est à direunsigned int
pour x86_32.Opérateur "moins" (<) ne peut être appliqué à deux opérandes de signe différent. Il n'y a tout simplement pas de ces opcodes, et la norme ne spécifie pas, si le compilateur peut faire implicite signe de conversion. Jusqu'à ce qu'il traite signé nombre non signés et émet un avertissement.
Il serait correct de l'écrire comme
ou même plus vite
size_t
. Son eststd::vector< THING >::size_type
.std::size_t
etstd::vector<T>::size_type
.std::allocator<T>
) est utilisé, alorssize_type == std::size_t
. Pour personnalisé allocateurs,size_type
pourrait être autre chose questd::size_t
.Idéalement, je voudrais utiliser une construction comme ceci à la place:
Cela a un très net avantage que votre code devient tout à coup un conteneur agnostique.
Et en ce qui concerne votre problème, si certains de bibliothèque que vous utilisez vous oblige à utiliser
int
où ununsigned int
serait un meilleur ajustement, de leur API est en désordre. De toute façon, si vous êtes sûr que cesint
sont toujours positifs, vous pouvez juste faire:Qui permettra de préciser clairement votre intention de le compilateur: il ne sera pas vous embêter avec des avertissements plus.
static_cast<int>(things.size())
pourraient être les solutions, si il n'y a pas d'autres.#pragma warning(push) #pragma warning(disable: 4018) /* ... function */ #pragma warning(pop)
) plutôt que d'utiliser une inutile de fonte. (Jette cacher légitime erreurs, m'kay? 😉 )Si vous ne pouvez pas/ne pas utiliser des itérateurs et si vous ne pouvez pas/ne pas utiliser
std::size_t
pour l'indice de boucle, faire un.size()
àint
la fonction de conversion des documents de l'hypothèse et de la conversion explicite silence l'avertissement du compilateur.Ensuite, vous écrivez votre boucle comme ceci:
L'instanciation de ce modèle de fonction sera presque certainement être insérée. Dans les versions de débogage, l'hypothèse sera vérifiée. Dans les versions release, il ne sera pas et le code sera aussi rapide que si vous l'avez appelé size() directement. Ni la version produira un message d'avertissement du compilateur, et c'est une légère modification de la idiomatiques boucle.
Si vous voulez attraper l'hypothèse échecs dans la version ainsi, vous pouvez remplacer l'affirmation d'une instruction if qui jette quelque chose comme
std::out_of_range("container size exceeds range of int")
.Noter que cela résout à la fois le signed/unsigned de comparaison ainsi que le potentiel
sizeof(int)
!=sizeof(Container::size_type)
problème. Vous pouvez laisser tous vos messages d'avertissements activés et les utiliser pour attraper les vrais bugs dans d'autres parties de votre code.Vous pouvez utiliser:
Par exemple:
Je peux également proposer la solution suivante pour le C++11.
(C++ n'est pas assez intelligent pour auto p = 0, de sorte que je dois mettre p = 0U....)
for (auto thing : vector_of_things)
si vous n'avez pas besoin de l'index.size()
retourne un type plus grand que unsigned int, ce qui est extrêmement commun.Je vais vous donner une meilleure idée
decltype
estDonc, Il en déduit le type de
things.size()
eti
sera un type comme même quethings.size()
. Donc,i < things.size()
sera exécuté sans aucun avertissementJ'ai eu un problème similaire. À l'aide de size_t ne fonctionnait pas. J'ai essayé l'autre qui a travaillé pour moi. (ci-dessous)
Je voudrais juste faire