12
votes

Que devriez-vous arriver à la négation d'une taille_t (c'est-à-dire-`-Sizeof (struct foo)`))?

Je traite du code au travail qui inclut une expression de la forme xxx

i.e. La négation d'un taille_t , et je ne suis pas clair sur ce que les normes C et C ++ exigent des compilateurs lorsqu'ils voient cela. Spécifiquement, de regarder autour d'ici et ailleurs, Tailleof renvoie une valeur intégrale non signée du type Taille_t . Je ne trouve aucune référence claire pour un comportement spécifié lors de la négation d'un entier non signé. Y a-t-il, et si oui, qu'est-ce que c'est?

Edit: OK, il y a donc de bonnes réponses concernant l'arithmétique sur des types non signés, mais ce n'est pas clair que cela est en fait telle. Lorsque cela ne nie, utilise-t-il sur un entier non signé ou converti sur un type signé et fais-il quelque chose avec cela? Est le comportement à attendre des normes "imaginez qu'il s'agit du nombre négatif d'une ampleur similaire, puis d'appliquer les règles" Overflow "pour les valeurs non signées"?


6 commentaires

Est-ce que je veux connaître la raison pour laquelle une telle chose a été apportée dans ce monde?


@Ejames: probablement pas, mais il existe certainement des raisons «justes» de faire une telle chose, telles que l'utilisation de valeurs négatives pour signifier une interprétation différente de la magnitude. Avant que quelqu'un m'empêche d'optimiser prématuré, celui-ci) n'est pas un code que j'ai écrit; et b) fait partie de l'exécution d'un environnement de programmation parallèle, dont l'une des applications représente environ 20% de temps sur les supercalculateurs NSF. En d'autres termes, chaque cycle compte.


Est-ce que cela fait une négation ou est-ce le côté droit d'une soustraction? Toute la déclaration serait probablement utile.


C'est une négation. Je vais faire cela explicite.


Mais juste faire une négation ne fait rien dans c - il sera probablement optimisé. Quelle est la négation réellement utilisée? Vous pouvez sûrement poster la déclaration complète qui l'utilise?


@Neil: Que se passe-t-il avec le résultat de cette expression n'est pas ce que je ne pouvais pas comprendre. Je connais les règles de conversion ailleurs. Ce type d'expression était un exemple dans lequel je ne l'ai pas fait.


6 Réponses :


2
votes

http://msdn.microsoft.com /en-us/library/wxxx8d2t%28vs.80%29.aspx

négation unie des quantités non signées est effectué en soustrayant la valeur de l'opérande de 2 n , où n est le Nombre de bits dans un objet de la donné de type non signé. (Microsoft C ++ fonctionne sur des processeurs qui utilisent deux-complément arithmétique. Sur d'autres processeurs, l'algorithme de négation peut différer.)

En d'autres termes, le comportement exact sera spécifique à une architecture. Si j'étais vous, j'éviterais d'utiliser une construction aussi étrange.


9 commentaires

Est-ce que c'est juste la façon dont Microsoft le fait ou le fait-il de cela comme c'est défini la mise en œuvre?


J'ai trouvé cette page quand je cherchais et souhaitais que cela ait dit quelque chose à propos de la partie de la norme qu'elle repose. Il suggère que cela ne soit pas strictement défini, mais est-il "indéfini", "mise en œuvre définie", inflexible ou autre chose? De plus, je pense que le texte que vous citez est légèrement erroné. Qui devrait être soustraire de 2 ^ n


Je n'ai pas accès à la norme C, mais GCC se comporte également de cette façon (sur x86). Malheureusement, je n'ai pas accès à un système qui utilise une représentation de non-compléments pour les nombres négatifs à tester. Si je me souviens bien, les représentations entières sont définies par la mise en œuvre, ce serait donc aussi.


ISO 14882: 2003 5.3.1.7 dit essentiellement la même chose, mais n'inclut pas la mise en garde des machines de complément des non-deux.


@outis: Pourriez-vous citer le texte en question, éventuellement dans une réponse séparée? Ce pourrait être ce que j'entre vraiment.


@Novelocrat: fait, mais comme un commentaire pour la réponse de Pavel, comme il est déjà là déjà là.


@outis: La réponse de Pavel n'était vraiment pas ce dont j'avais besoin. Le texte de normes que vous avez trouvé était.


Le comportement exact est effectivement défini à la fois par la norme C et la norme C ++. Le commentaire de Microsoft donne le même résultat, à moins que l'entier ne soit 0 (selon Microsoft -0U serait 2 ^ 32 si un non signé INT est 32 bit qui est un non-sens). Selon la norme C et C ++, -x pour non signé x calcule la valeur mathématique, puis ajoute de plusieurs fois de manière ou soustrait uint_max + 1 jusqu'à ce que le résultat soit dans la plage de droite.


Le comportement de l'arithmétique non signé ne dépend pas de savoir si les entiers signés sont représentés à l'aide de deux-complément ou non. Cependant, il existe des cas où l'arithmétique signée peut être pertinente (voir Ma réponse ).



21
votes

L'ISO C et les normes ISO C garantit que l'arithmétique non signé est modulo 2 n - à savoir, pour tout dépassement positif ou négatif, il "enroule autour". ISO C ++, c'est 3.9.1 [basic.fundamental] / 4:

entiers non signés, déclarée unsigned , doit obéir aux lois de l'arithmétique modulo 2 n n est le nombre de bits dans la représentation de la valeur de cette taille particulière de nombre entier. 41

...

41) Cela implique que l'arithmétique non signé ne déborde pas, car un résultat qui ne peut pas être représenté par l'entier non signé résultant type est réduit modulo le nombre qui est plus grand que la plus grande valeur qui peut être représentée par le nombre entier sans signe résultant le type.

ISO C (99), il est 6.2.5 / 9:

Un calcul impliquant opérandes non signés ne peut jamais déborder, car un résultat qui ne peut pas être représenté par le type entier non signé résultant est réduit modulo le nombre qui est plus grand que la plus grande valeur qui peut être représentée par le type résultant.

Ce qui signifie que le résultat est assuré d'être le même que SIZE_MAX -. (Sizeof (struct foo)) + 1


Dans la norme ISO 14882: 2003 5.3.1.7:

[...] Le négatif d'un non signé la quantité est calculée en soustrayant sa valeur de 2 n , où n est le nombre de bits l'opérande a rendues. Le type de le résultat est le type de promotion opérande.


3 commentaires

Ajouter en ISO 14882: 2003 5.3.1.7: "[...] 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 configuré. Le type de résultat est le type de l'opérande promu. "


Cette dernière partie est ce qui est le plus pertinent pour la question que j'ai posée, bien que la partie précédente montre comment elle est cohérente avec l'approche prise ailleurs dans la norme.


Ce n'est pas nécessairement 100%. Voir Ma réponse pour un cas inhabituel où il pourrait ne pas être.



1
votes

La seule chose que je peux penser est tellement tort qu'elle me fait mal la tête ...

size_t size_of_stuff = sizeof(stuff);

if(I want to subtract the size)
    size_of_stuff = -sizeof(stuff);

size_t total_size = size_of_stuff + other_sizes;


1 commentaires

Vous pouvez imaginer un peu trop étroitement. Supposons que le résultat de l'expression soit attribué à un int ou long - un type signé.




2
votes

Négéser un numéro non signé est utile pour propager le LSB à travers le mot pour former un masque pour les opérations bitwises ultérieures.


0 commentaires

1
votes

Taille_t code> est un type d'entier non signé non signé défini par la mise en oeuvre.

négativement a Taille_t code> Valeur probablement em> vous donne le résultat de type taille_t code> avec le comportement habituel non signé du modulo. Par exemple, en supposant que taille_t code> est de 32 bits et tailleOf (struct foo) == 4 code>, puis -Sizeof (struct foo) == 4294967292 code> , ou 2 32 sup> -4. p>

sauf une chose: l'opérateur Unary - code> applique les promotions entier em> (c> ) Ou Promotions intégrales em> (C ++) (elles sont essentiellement la même chose) à son opérande. Si taille_t code> est au moins aussi large que int code>, cette promotion ne fait rien, et le résultat est de type taille_t code>. Mais si int code> est plus large que Taille_t code>, de sorte que int_max> = Taille_max code>, puis l'opérande de - code> est " Promu "de taille_t code> à int code>. Dans cet étui improbable, -sizeof (struct foo) == -4 code>. P>

Si vous attribuez cette valeur à un objet Taille_T code>, puis sera converti sur Taille_t code>, produisant la valeur Taille_MAX-4 CODE> Valeur que vous attendriez. Mais sans une telle conversion, vous pouvez obtenir des résultats surprenants. P>

Maintenant, je n'ai jamais entendu parler d'une implémentation où taille_t code> est étroit que int code>, Donc, vous n'êtes pas susceptible de courir dans cela. Mais voici un cas d'essai, en utilisant abrégé non signé code> en tant que stand-in pour l'hypothétique Taille_t code> Type, qui illustre le problème potentiel: P>

sizeof (foo) = 4
-sizeof (foo) = 18446744073709551612
sizeof_foo = 4
-sizeof_foo = -4


4 commentaires

Il existe certains contrôleurs intégrés où la RAM est subdivisée en blocs non consécutifs de moins de 256 octets chacun, et que, à moins qu'un programme contienne un objet plus grand que celui de ROM Taille_T pourrait très raisonnablement être un "caractère non signé" 8 bits (ce qui est bien sûr plus petit que "INT"). Je pense que la plupart des compilateurs de ces compilateurs font en fait la taille_t un Int non signé en raison de l'attente qu'il se comporte comme un. C'est dommage que la norme ne décrit même pas le comportement normatif pour de telles choses, car il est idiot de faire plier les programmeurs en arrière pour accueillir des mises en œuvre pouvant même exister.


@supercat: la norme fait décrit le comportement normatif pour de telles choses: des types non signés plus étroits que int sont favorisés à int . Ce n'est tout simplement pas le comportement que vous préféreriez. (Ni clair, est-ce le comportement que je préférerais?)


La norme pourrait très facilement spécifier que les implémentations où ze_t figure ci-dessous int doit être considéré comme non normatif; Les implémentations qui doivent se comporter de cette manière pour une raison quelconque (la compatibilité avec le code existant) serait autorisée à le faire, mais les implémentations seraient fortement encouragées à faire ze_t être au moins aussi grand que non signé int absent une raison impérieuse à faire autrement (par exemple, la compatibilité avec le code existant). Je ne peux penser à aucune raison technique pour laquelle une implémentation ne serait pas capable de faire ze_t être au moins aussi large que non signé INT ; peut tu?


Au-delà des problèmes de comportement signés et non signés, considérons également que même si un système ne peut pas affecter un objet sur une taille (par exemple 255 octets), il devrait toujours vérifier les bits supérieurs de la taille demandée pour s'assurer qu'ils sont nuls et renvoyez NULL s'ils ne sont pas, plutôt que de répondre à une demande de 264 octets avec une allocation de huit ans.