31 votes

Pourquoi 'auto' ne respecte-t-il pas l'opérateur unaire moins ?

Je suis assez novice 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'ai utilisé l'opérateur unaire moins à 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 au courant de size_t étant un int non signé.

J'ai essayé cela avec GCC 8.1.0 et C++17.

9 votes

Pourquoi vous attendriez-vous à quelque chose de différent ? La même chose se produit lorsque vous faites cout << -(sizeof(a)) << endl; . Cela n'a rien à voir avec l'automobile.

0 votes

Je pensais que auto ne se contente pas de respecter le type de retour, mais effectue une sorte de vérification du contexte, comme la vérification de l'opérateur unaire moins ou tout ce qui se passe dans le processus d'initialisation.

5 votes

Parce que les concepteurs de C voulaient - pour être valide sur les valeurs non signées. Personnellement, je l'aurais rendu invalide.

28voto

VTT Points 27056

Le problème réel ici est que l'utilisation de l'opérateur moins unaire, tout comme le reste des opérateurs arithmétiques intégrés, est sujette à l'approbation de la Commission européenne. promotions intégrales . Il est donc surprenant que le résultat de l'application du moins unaire à size_t sera toujours size_t et il n'y a pas besoin de blâmer auto .

Contre-exemple. Dans ce cas, en raison des promotions intégrales de type x sera int donc la sortie sera -1 :

unsigned short a{1};
auto x{-a};
cout << x << endl;

0 votes

Tu ne veux pas dire un -surprenant ?

3 votes

@acraig5075 Non, je veux dire de manière surprenante. C'est plutôt déroutant de savoir pourquoi le moins unaire est autorisé à être appliqué au type non signé en premier lieu. Je veux dire que le moins unaire est censé changer le signe de la valeur, mais les valeurs non signées ne peuvent pas avoir le signe changé.

2 votes

Le moins binaire de VTT est applicable aux valeurs non signées, alors pourquoi le moins unaire ne le serait-il pas ?

21voto

Stephan Lechner Points 29375

Votre expression -(sizeof(a)) applique la méthode unaire - à 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 chez cppreference.com ):

L'opérateur unaire moins construit calcule la négative de son opérande promu. Pour un a non signé, la valeur de -a est 2^b -a, où b est le nombre de bits après la promotion.

Ainsi, même si cela peut être surprenant, auto fonctionne correctement, comme le résultat de l'application de l'unaire - à une valeur non signée reste une valeur non signée.

4 votes

" L'opérateur ne transforme pas une valeur intégrale non signée en une valeur signée. " Ce qui est tout à fait logique si l'on utilise les non signés pour l'arithmétique modulo et n'a aucun sens si l'on utilise les non signés pour les nombres naturels.

0 votes

Vous aimeriez peut-être mentionner que size_t comme tous les types intégraux est soumis à la promotion intégrale, donc s'il est plus petit que int il sera promu à int avant que le moins unaire ne l'obtienne. Mais je ne connais pas d'implémentation aussi perverse.

4voto

Caleth Points 17517

Le résultat de (unaire) - appliquée à une valeur non signée est non signée, et sizeof renvoie une valeur non signée.

L'opérande de l'opérateur unaire - doit être d'un type arithmétique ou d'un type d'énumération non scopé. et le résultat est la négation de son opérande. La promotion intégrale est effectuée sur des opérandes de type intégral ou énumération. La négation d'une quantité non signée est calculée en soustrayant sa valeur de 2^n, où n est la valeur de l'opérateur. de 2^n, où n est le nombre de bits de l'opérande promu. Le type du résultat est le type de l'opérande promu.

[expr.unary.op]

Le résultat de sizeof y sizeof... est une constante de type std::size_­t

[expr.sizeof]

Pour éviter le 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. représentée dans le type de destination ; sinon, la valeur est définie par l'implémentation.

[conv.integral]

class A{};

int main() {
    A a;
    auto x = -(int{sizeof(a)});
    cout << x << endl;
    return 0;
}

0 votes

Merci de montrer le auto x = 0-(sizeof(a)); manière.

0 votes

Si size_t a une portée plus grande que int (c'est presque toujours le cas), alors, étant donné size_t x,y=...; entonces x=-y; définira x au seul possible size_t valeur qui rendrait x+y rendement 0.

1voto

Giovanni Terlingen Points 2027

Si nous jetons un coup d'oeil : 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 un signed int pour autoriser les valeurs négatives.

Au lieu de auto vous pouvez écrire int qui autorise les valeurs négatives.

0 votes

Donc, je dois le faire en disant explicitement que c'est un signed int ? Est-ce que auto toujours utiliser uniquement le type de retour sans vérifier si cela a un sens ? Si c'est le cas, je vois un problème avec le casting ici.

0 votes

Exactement, vous devez déclarer c++ que vous allez stocker une valeur négative. auto n'est pas au courant puisque la valeur a été size_t . Le moulage ne vous posera pas de problème puisque vous dites c++ il s'agira d'un signed int .

0 votes

@CodeShark Qu'est-ce qui n'a pas de "sens" ici ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X