int vs size_t sur 64 bits
Le portage de code de 32 bits à 64 bits. Beaucoup d'endroits avec
int len = strlen(pstr);
Ces tous de générer des avertissements maintenant, parce que strlen() retourne size_t qui est 64 bits et int est toujours en 32 bits. J'ai donc été en les remplaçant par
size_t len = strlen(pstr);
Mais je viens de réaliser que ce n'est pas sûr, comme un size_t est pas signé et il peut être traité comme signé par le code (je l'ai fait, couru dans un cas où il a causé un problème, je vous remercie, tests unitaires!).
Aveuglément casting strlen retour (int) se sent sale. Ou peut-être il ne devrait pas?
La question est donc: est-il une solution élégante pour cela? J'ai probablement un millier de lignes de code comme ça dans le code, je ne peux pas vérifier manuellement chaque un d'eux et la couverture de test est actuellement quelque part entre 0,01 et 0,001%.
L'exemple est probablement quelque chose le long des lignes de:
len--; if (len < 0) { break }
OriginalL'auteur MK. | 2010-03-25
Vous devez vous connecter pour publier un commentaire.
Comme un compromis, vous pouvez utiliser
ssize_t
(si disponible). Faux, si non, en utilisantlong long
,int_fast64_t
,intmax_t
, ou d'avoir une plate-forme de portage en-tête qui permet à un type approprié être spécifié pour une plate-forme.ssize_t
est pas dans POSIX standard C ou C++, mais si vous avez jamais touché à une plate-forme qui n'a pas un type signé de la même taille quesize_t
ensuite, j'éprouve de la sympathie.D'un plâtre pour
int
est presque sûr (en supposant 32 bits int sur votre plate-forme 64 bits, ce qui semble raisonnable), parce qu'une chaîne est peu probable à plus de 2^31 octets de long. Un casting pour un plus grand type signé est encore plus sûr. Les clients qui peuvent se permettre 2^63 octets de mémoire, ce qui est connu dans le commerce comme "un bon problème à avoir" 😉Bien sûr, vous pouvez vérifier:
Sûr qu'il ya une surcharge, mais si vous avez 1000 cas alors ils ne peuvent pas tous être la performance est critique. Pour ceux qui sont (le cas échéant), vous pouvez faire le travail pour étudier si
len
signée en fait des questions. Si cela ne fonctionne pas, passer àsize_t
. Si elle le fait, de réécriture ou de il suffit de prendre un risque de ne jamais rencontre un objet qui ridiculement énorme. Le code d'origine aurait certainement fait quelque chose de mal tout de même sur la plate-forme 32 bits, silen
avait été négatif, comme un résultat destrlen
de retourner une valeur plus grande queINT_MAX
.doivent être de taille égale à
size_t
Je pense que l'intention générale de
ssize_t
est que, dans la pratique, POSIX implémentations ne vont pas permettre à des objets individuels de plus de la moitié de la taille de l'espace d'adressage disponible. Il est assez facile à appliquer c'estmalloc
, bien que je ne pense pas que c'est garanti. Il est utile d'avoir signé une taille type pour représenter les décalages qui sont autorisés à être négatif.par "grand", il signifie que
SIZE_MAX > SSIZE_MAX
, donc une valeur pourraient être plus grands. Non pas que le type est plus grand.OriginalL'auteur Steve Jessop
Il y a quelques temps j'ai posté une petite remarque sur ce genre de questions sur mon blog et la réponse courte est:
Toujours utiliser la bonne C++ types d'entiers
Réponse longue:
Lors de la programmation en C++, c'est une bonne idée d'utiliser les bons types d'entiers pertinentes au contexte particulier. Un peu de rigueur paie toujours en arrière. Il n'est pas rare de voir une tendance à ignorer l'intégrale des types définis comme propres à conteneurs standard, à savoir size_type. Il est disponible pour le numéro de conteneur standard comme std::string ou std::vector. Cette ignorance peut obtenir sa vengeance facilement.
Ci-dessous est un exemple simple d'utilisation d'un type utilisé pour attraper résultat de std::string::trouver la fonction. Je suis sûr que beaucoup pouvait s'y attendre il n'y a rien de mal avec le unsigned int ici. Mais, en fait, c'est juste un bug. J'ai tourner Linux sur architecture 64 bits et quand je compile ce programme, il fonctionne comme prévu. Cependant, lorsque je remplace la chaîne en ligne Un avec abc, il fonctionne toujours mais pas comme prévu 🙂
Corriger est très simple. Il suffit de remplacer unsigned int avec std::string::size_type. Le problème pourrait être évité si quelqu'un qui a écrit ce programme a pris soin de l'utilisation du bon type. Pour ne pas mentionner que le programme soit portable tout de suite.
J'ai vu ce genre de questions tout à fait à plusieurs reprises, notamment dans le code écrit par d'anciens programmeurs C qui n'aiment pas porter le museau de la rigueur du C++ types de système impose et exige. L'exemple ci-dessus est une banale, mais je crois qu'elle présente à la racine du problème.
Je recommande brillant article De développement 64 bits écrit par Andrey Karpov où vous pouvez trouver un beaucoup plus sur le sujet.
std::some_container::size_type
se résume àsize_t
dans tous les honnêtes implémentations. Aussi loin que je peux voir, au moinsstd::bitset::size_type
,std::array::size_type
,std::initializer_list
, etstd::allocator::size_type
sont typedefs poursize_t
. Donc, sauf si vous utilisez un fou allocateur ou très spécial paramètres du modèle,size_t
est suffisant.OriginalL'auteur mloskot
Réglage de l'avertissements du compilateur pour le niveau maximal devrait vous obtenir un rapport de chaque signe incorrect de conversion. Dans gcc, '-Wall-Wextra " devrait faire.
Vous pouvez également utiliser un analyseur de code statique comme cppcheck pour voir si tout est bon.
OriginalL'auteur pau.estalella
Vous pouvez utiliser
ssize_t
(signé variante desize_t
).OriginalL'auteur caf
Vous pouvez traiter site_t signé en toute sécurité dans la plupart des cas. La unsigned size_t seront considérés comme négatifs seulement lorsqu'il (ou les résultats intermédiaires dans les expressions) est plus grande que 2^31 (32-bit) ou 2^63 64 bits.
Mise à JOUR:
Désolé, size_t sera dangereux dans les constructions comme
while ( (size_t)t >=0 )
. Donc, la bonne réponse est à utiliserssize_t
.boucle
while (len>0)
doit s'arrêter aulen == 0
. S'il vous plaît, montrez-nous votre exemple, le problème a été détecté avec les tests unitaires.Bla, désolé, je voulais dire si (nbcar < 0). J'avais une boucle avec l'inverse de vérifier "si (nbcar < 0) passez à quelque chose;" au lieu de "if (len >= 0) faire quelque chose;"
OriginalL'auteur osgx
Si votre compilateur prend en charge le c++0x:
OriginalL'auteur Johan