Ma question est que
J'ai une taille_t données, mais maintenant je veux le convertir en double ou int.
Si je fais quelque chose comme
size_t data = 99999999;
int convertdata = data;
le compilateur signalera un avertissement. parce que peut-être déborder.
Avez-vous une méthode comme le boost ou une autre méthode pour convertir?
Un casting, comme suggéré par Blaz Bratanic :
size_t data = 99999999;
int convertdata = static_cast<int>(data);
est susceptible de faire taire l'avertissement (bien qu'en principe un compilateur puisse avertir de tout ce qu'il veut, même s'il y a un casting).
Mais cela ne résout pas le problème évoqué par l'avertissement, à savoir qu'une conversion de size_t
à int
pourrait vraiment déborder.
Si possible, concevez votre programme de manière à ne pas convertir pour convertir un size_t
valeur à int
. Il suffit de le stocker dans un size_t
variable (comme vous l'avez déjà fait) et utilisez-le.
La conversion en double
ne provoquera pas de dépassement de capacité, mais cela pourrait entraîner une perte de précision pour un très grand size_t
valeur. Encore une fois, il n’a pas beaucoup de sens de convertir un size_t
à un double
; il vaut mieux garder la valeur dans un size_t
variable.
( Réponse de R Sah a quelques suggestions si vous ne pouvez pas éviter le casting, telles que le lancement d'une exception lors d'un débordement.)
Fonte statique:
static_cast<int>(data);
Si votre code est prêt à gérer les erreurs de débordement, vous pouvez lever une exception si data
est trop volumineux.
size_t data = 99999999;
if ( data > INT_MAX )
{
throw std::overflow_error("data is larger than INT_MAX);
}
int convertData = static_cast<int>(data);
Vous pouvez utiliser Boost numeric_cast
.
Cela lève une exception si la valeur source est en dehors des limites du type de destination, mais ne détecte pas de perte de précision lors de la conversion en double
.
Quelle que soit la fonction que vous utilisez, vous devez toutefois décider de ce que vous voulez qu'il se passe dans le cas où la valeur dans le size_t
est supérieur à INT_MAX
. Si vous voulez le détecter, utilisez numeric_cast
ou écrivez votre propre code pour vérifier. Si vous savez que cela ne peut pas arriver, vous pouvez utiliser static_cast
pour supprimer l'avertissement sans le coût d'une vérification de l'exécution, mais dans la plupart des cas, le coût importe peu.
En supposant que le programme ne puisse pas être repensé pour éviter la distribution (réf. réponse de Keith Thomson ):
Pour convertir de size_t en int, vous devez vous assurer que size_t ne dépasse pas la valeur maximale de int. Cela peut être fait en utilisant std :: numeric_limits :
int SizeTToInt(size_t data)
{
if (data > std::numeric_limits<int>::max())
throw std::exception("Invalid cast.");
return std::static_cast<int>(data);
}
Si vous avez besoin de convertir de size_t en double et de ne pas perdre en précision, je pense que vous pouvez utiliser une distribution étroite (réf. Stroustrup: langage de programmation C++, quatrième édition):
template<class Target, class Source>
Target NarrowCast(Source v)
{
auto r = static_cast<Target>(v);
if (static_cast<Source>(r) != v)
throw RuntimeError("Narrow cast failed.");
return r;
}
J'ai testé l'utilisation de la conversion étroite pour les conversions taille_t-en-double en inspectant les limites du nombre entier maximal d'entiers en nombres à représenter en virgule flottante (le code utilise googletest):
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 2 })), size_t{ IntegerRepresentableBoundary() - 2 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() - 1 })), size_t{ IntegerRepresentableBoundary() - 1 });
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() })), size_t{ IntegerRepresentableBoundary() });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 1 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 2 })), size_t{ IntegerRepresentableBoundary() + 2 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 3 }), std::exception);
EXPECT_EQ(static_cast<size_t>(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 4 })), size_t{ IntegerRepresentableBoundary() + 4 });
EXPECT_THROW(NarrowCast<double>(size_t{ IntegerRepresentableBoundary() + 5 }), std::exception);
où
constexpr size_t IntegerRepresentableBoundary()
{
static_assert(std::numeric_limits<double>::radix == 2, "Method only valid for binary floating point format.");
return size_t{2} << (std::numeric_limits<double>::digits - 1);
}
Autrement dit, si N est le nombre de chiffres de la mantisse, pour les doublons inférieurs ou égaux à 2 ^ N, les entiers peuvent être représentés exactement. Pour les doubles entre 2 ^ N et 2 ^ (N + 1), un entier sur deux peut être représenté exactement. Pour les doublons entre 2 ^ (N + 1) et 2 ^ (N + 2), un entier sur quatre peut être représenté exactement, et ainsi de suite.