Je suis assez nouveau en C++ mais je trouve ce comportement de auto
bizarre:
class A{};
int main() {
A a;
auto x = -(sizeof(a));
cout << x << endl;
return 0;
}
La variable x est unsigned
dans ce cas, bien que j'aie utilisé l'opérateur unaire moins lors de l'initialisation de la variable. Comment se fait-il que seul le type de retour de sizeof
(std::size_t
) est pris en compte mais pas le fait que le nombre stocké sera négatif à cause de l'opérateur utilisé?
Je suis conscient de size_t
étant un entier non signé.
J'ai essayé cela avec GCC 8.1.0 et C++ 17.
Le problème réel ici est que l'utilisation de l'opérateur unaire moins, tout comme le reste des opérateurs arithmétiques intégrés, est soumise à promotions intégrales. Étonnamment, le résultat de l'application d'un signe moins unaire à size_t
sera toujours size_t
et il n'est pas nécessaire de blâmer auto
.
Contre-exemple. Dans ce cas, en raison des promotions intégrées, le type de x
sera int
donc la sortie sera -1
:
unsigned short a{1};
auto x{-a};
cout << x << endl;
Votre expression -(sizeof(a))
applique l'unaire -
opérateur à une valeur de type non signé. L'opérateur unaire ne transforme pas une valeur intégrale non signée en une valeur signée; il définit plutôt quelle valeur non signée sera le résultat d'une telle opération comme suit (cf. opérateurs arithmétiques unaires sur cppreference.com ):
L'opérateur unaire moins intégré calcule le négatif de son opérande promu. Pour a non signé, la valeur de -a est 2 ^ b -a, où b est le nombre de bits après la promotion.
Par conséquent, même si cela peut être surprenant, auto
fonctionne correctement, suite à l'application d'unaire -
L'opérateur d'une valeur non signée est toujours une valeur non signée.
Le résultat de (unaire) -
appliqué à une valeur non signée est non signé, et sizeof
renvoie une valeur non signée.
L'opérande de l'opérateur unaire doit avoir un type d'énumération arithmétique ou non étendue et le résultat est la négation de son opérande. La promotion intégrale est effectuée sur des opérandes intégraux ou d'énumération. Le négatif d'une quantité non signée est calculé en soustrayant sa valeur de 2 ^ n, où n est le nombre de bits dans l'opérande promu. Le type du résultat est le type de l'opérande promu.
Le résultat de
sizeof
etsizeof...
est une constante de typestd::size_t
Pour éviter un comportement défini par l'implémentation, vous devez convertir en int
avant d'appliquer le -
Si le type de destination est signé, la valeur est inchangée si elle peut être représentée dans le type de destination; sinon, la valeur est définie par l'implémentation.
class A{};
int main() {
A a;
auto x = -(int{sizeof(a)});
cout << x << endl;
return 0;
}
Si nous jetons un œil à: https://en.cppreference.com/w/cpp/language/sizeof , le résultat est de type size_t
qui est unsigned
. Vous devez explicitement le déclarer comme signed int
pour autoriser les valeurs négatives.
Au lieu de auto
, vous pouvez écrire int
qui autorise les valeurs négatives.