Vra

Veronderstel ek het die volgende C-kode.

unsigned int u = 1234;
int i = -5678;

unsigned int result = u + i;

Watter implisiete doelskoppe is hier aan die gang, en is hierdie kode veilig is vir alle waardes van u en i?(Veilig, in die sin dat selfs al hiervan in hierdie voorbeeld sal oorloop tot'n groot positiewe getal, kon ek gooi dit terug na'n int en kry die werklike resultaat.)

Was dit nuttig?

Oplossing

Kort Antwoord

Jou i sal wees omgeskakel om 'n ongetekende heelgetal deur die toevoeging van UINT_MAX + 1, dan is die toevoeging sal saam met die ongetekende waardes gedra, wat lei tot 'n groot result (afhangende van die waardes van u en i) .

Long Antwoord

Volgens die C99 Standard:

  

6.3.1.8 Gewone rekenkundige doelskoppe

     
      
  1. As beide operande het dieselfde tipe, dan nie verder bekering nodig is.
  2.   
  3. Andersins, indien beide operande heelgetal tipes onderteken of albei unsigned tipes heelgetal, die operand met die tipe van mindere heelgetal omskakeling rang omgeskakel word na die tipe van die operand met 'n groter rang.
  4.   
  5. Andersins, as die operand dat unsigned heelgetal tipe het het rang groter of gelyk is aan die rang van die tipe van die ander operand, dan die operand met onderteken heelgetal tipe omgeskakel word na die tipe van die operand met ongetekende heelgetal tipe.
  6.   
  7. Andersins, as die tipe van die operand met onderteken heelgetal tipe al die waardes van die tipe van die operand met ongetekende heelgetal tipe kan verteenwoordig, dan is die operand met ongetekende heelgetal tipe omgeskakel word na die tipe van die operand met onderteken heelgetal tipe.
  8.   
  9. Andersins, is albei operande omgeskakel word na die ongetekende heelgetal tipe wat ooreenstem met die tipe van die operand met onderteken heelgetal tipe.
  10.   

In jou geval, ons het 'n ongetekende int (u) en onderteken int (i). Met verwysing na (3) hierbo, aangesien beide operande dieselfde rang, jou i moet wees omgeskakel om 'n ongetekende heelgetal.

  

Geteken 6.3.1.3 en ongetekende heelgetalle

     
      
  1. Wanneer 'n waarde met heelgetal tipe omgeskakel word na 'n ander, behalwe _Bool heelgetal tipe, as die waarde kan voorgestel word deur die nuwe tipe, dit is onveranderd.
  2.   
  3. Andersins, as die nuwe tipe is unsigned, die waarde omgeskakel deur herhaaldelik te voeg of af te trek een meer as die maksimum waarde wat voorgestel kan word in die nuwe tipe totdat die waarde is in die reeks van die nuwe tipe.
  4.   
  5. Andersins, is die nuwe tipe onderteken en die waarde kan nie verteenwoordig in dit; óf die gevolg is-implementering omskryf of 'n-implementering gedefinieer sein opgewek.
  6.   

Nou moet ons verwys na (2) hierbo. Jou i sal omgeskakel word na 'n ongetekende waarde deur die toevoeging van UINT_MAX + 1. So die gevolg sal afhang van hoe UINT_MAX word gedefinieer op jou implementering. Dit sal groot wees, maar dit sal nie oorloop nie, want:

  

6.2.5 (9)

     

'n berekening wat unsigned operande kan nooit oorloop, omdat 'n gevolg dat nie kan voorgestel word deur die gevolglike unsigned heelgetal tipe verminder modulo die getal wat is een groter as die grootste waarde wat voorgestel kan word deur die gevolglike tipe.

Bonus: Rekenkundige Gesprek Semi-WTF

#include <stdio.h>

int main(void)
{
  unsigned int plus_one = 1;
  int minus_one = -1;

  if(plus_one < minus_one)
    printf("1 < -1");
  else
    printf("boring");

  return 0;
}

Jy kan hierdie skakel gebruik om hierdie online probeer: https://repl.it/repls/QuickWhimsicalBytes

Bonus: Rekenkundige Gesprek Side Effect

Rekenkundige omskakeling reëls kan gebruik word om die waarde van UINT_MAX kry deur die initialiseren 'n ongetekende waarde aan -1, dit wil sê:

unsigned int umax = -1; // umax set to UINT_MAX

Dit is gewaarborg om ongeag die getekende aantal voorstelling van die stelsel as gevolg van die omskakeling reëls hierbo beskryf draagbare wees. Sien hierdie vraag SO vir meer inligting: is dit veilig om te gebruik -1 al stukkies gestel is?

Ander wenke

Gesprek uit onderteken om unsigned doen nie noodwendig net kopieer of herinterpreteer die verteenwoordiging van die getekende waarde. Vermelding van C standaard (C99 6.3.1.3):

  

Wanneer 'n waarde met heelgetal tipe omgeskakel word na 'n ander heelgetal tipe behalwe _Bool, indien   die waarde kan voorgestel word deur die nuwe tipe, dit is onveranderd.

     

Andersins, as die nuwe tipe is unsigned, die waarde omgeskakel deur herhaaldelik te voeg of   trek een meer as die maksimum waarde wat in die nuwe tipe kan voorgestel word   totdat die waarde is in die reeks van die nuwe tipe.

     

Andersins, die nuwe tipe is onderteken en die waarde kan nie verteenwoordig in dit; óf die   gevolg is-implementering omskryf of 'n-implementering gedefinieer sein opgewek.

Vir die twee se komplement voorstelling dis byna universele deesdae, die reëls ooreen met wending die stukkies. Maar vir ander voorstellings (teken-en-grootte of aanvulling kinders '), moet die implementering C nog reël vir dieselfde resultaat, wat beteken dat die omskakeling van die stukkies nie net kan kopieer. Byvoorbeeld, (unsigned) -1 == UINT_MAX, ongeag van die verteenwoordiging.

In die algemeen, doelskoppe in C gedefinieer om te werk op waardes, nie op vertoë.

Om die oorspronklike vraag te beantwoord:

unsigned int u = 1234;
int i = -5678;

unsigned int result = u + i;

Die waarde van i omgeskakel word na unsigned int, opbrengs UINT_MAX + 1 - 5678. Hierdie waarde word dan bygevoeg by die ongetekende waarde 1234, opbrengs UINT_MAX + 1 - 4444.

(In teenstelling met ongetekende oorloop, onderteken oorloop beroep op undefined gedrag wraparound is algemeen, maar word nie gewaarborg nie deur die C standaard -.. En samesteller optimalisaties kan saai verwoesting op-kode wat ongegrond aannames maak)

Met verwysing na die Bybel :

  • Jou Daarbenewens werking veroorsaak dat die int word omgeskakel na 'n ongetekende int.
  • Die aanvaarding van twee se komplement voorstelling en ewe groot tipes, die bietjie patroon verander nie.
  • Gesprek van unsigned int te onderteken int is implementering afhanklik. (Maar dit waarskynlik werk die manier waarop jy verwag op die meeste platforms deesdae.)
  • Die reëls is 'n bietjie meer ingewikkeld in die geval van 'n kombinasie onderteken en unsigned van verskillende groottes.

As 'n mens unsigned en een onderteken veranderlike bygevoeg (of enige binêre operasie) albei implisiet omgeskakel word na unsigned, wat sou in hierdie geval lei tot 'n groot gevolg.

Dit is dus veilig in die sin van dat die uitslag dalk groot en verkeerd wees, maar dit sal nooit crash.

Wanneer die omskakeling van onderteken om unsigned is daar twee moontlikhede. Nommers wat oorspronklik positiewe was bly (of geïnterpreteer as) dieselfde waarde. Aantal wat oorspronklik negatiewe was sal nou geïnterpreteer word as groter positiewe nommers.

Soos voorheen beantwoord, kan jy heen en weer tussen gooi onderteken en unsigned sonder 'n probleem. Die grens geval vir onderteken heelgetalle is -1 (0xFFFFFFFF). Probeer optel en aftrek van wat en jy sal vind dat jy terug kan gooi en dit korrek wees.

As jy egter gaan heen en weer word giet, ek sou raai die name van jou veranderlikes soos wat dit duidelik watter tipe hulle is, bv:

int iValue, iResult;
unsigned int uValue, uResult;

Dit is veels te maklik om te kry afgelei deur meer belangrike kwessies en vergeet wat veranderlike is watter tipe as hulle die naam sonder 'n wenk. Jy wil nie 'n ongetekende as 'n skikking indeks te gooi en dan gebruik dit.

  

Wat implisiete doelskoppe is hier aan die gang,

Ek sal omgeskakel word na 'n ongetekende heelgetal.

  

en is hierdie kode veilig vir alle waardes van u en ek?

Veilige in die sin dat hulle ja goed gedefinieerde (sien https://stackoverflow.com/a/50632/5083516).

Die reëls is geskryf in tipies hard aan standaarde-praat, maar in wese alles verteenwoordiging is gebruik in die getekende heelgetal die ongetekende heelgetal sal 'n 2 se komplement voorstelling van die aantal bevat lees.

Optel, aftrek en vermenigvuldiging sal goed werk op hierdie nommers wat lei tot 'n ander unsigned heelgetal bevat 'n twee-twee aanvulling getal wat die "regte gevolg".

afdeling en giet om groter unsigned tipes heelgetal sal het goed gedefinieerde resultate, maar die resultate sal nie 2 se komplement voorstelling van die "werklike resultaat".

  

(Safe, in die sin dat selfs al is gevolg in hierdie voorbeeld sal oorloop na 'n paar groot positiewe getal, kon ek dit terug gegooi na 'n int en kry die werklike resultaat.)

Hoewel doelskoppe uit onderteken om unsigned word gedefinieer deur die standaard die omgekeerde is-implementering gedefinieer beide gcc en MSVC definieer die sukses so dat jy die "regte resultaat" sal kry wanneer die omskakeling van 'n 2 se komplement aantal gestoor in 'n ongetekende heelgetal terug na 'n getekende heelgetal. Ek verwag dat jy sal net 'n ander gedrag op obskure stelsels wat nie 2 se aanvulling hoef te gebruik vir onderteken heelgetalle te vind.

https://gcc.gnu.org/onlinedocs /gcc/Integers-implementation.html#Integers-implementation https://msdn.microsoft.com/en-us/library/0eex498h. ASPX

Verskriklike Antwoorde In Oorvloed

Ozgur Ozcitak

Wanneer jy gooi uit onderteken te unsigned (en andersom) die interne voorstelling van die getal nie verandering.Watter veranderinge is hoe die samesteller interpreteer die teken bietjie.

Dit is heeltemal verkeerd.

Matte Fredriksson

Wanneer een unsigned en een onderteken veranderlike is bygevoeg (of enige binêre die operasie) beide is implisiet omgeskakel na unsigned, wat sou in hierdie geval gevolg in'n groot gevolg.

Dit is ook verkeerd.Ongetekende ints kan word bevorder tot ints moet hulle gelyk presisie as gevolg van padding stukkies in die ongetekende tipe.

smh

Jou bykomend werking veroorsaak dat die int om te omgeskakel word na'n ongetekende int.

Verkeerd.Miskien is dit nie, en miskien is dit nie.

Omsetting van unsigned int te onderteken int implementering is afhanklik.(Maar dit is waarskynlik werk die manier waarop jy verwag op die meeste platforms hierdie dae.)

Verkeerd.Dit is óf ongedefinieerde gedrag as dit veroorsaak oorloop of die waarde is bewaar.

Anonieme

Die waarde van ek is omgeskakel na ongetekende int ...

Verkeerd.Hang af van die akkuraatheid van'n int relatief tot'n ongetekende int.

Taylor Prys

Soos voorheen beantwoord, kan jy gooi heen en weer tussen onderteken en ongetekende sonder'n probleem.

Verkeerd.Probeer om te slaan'n waarde buite die omvang van'n onderteken heelgetal resultate in ongedefinieerde gedrag.

Nou kan ek uiteindelik die vraag beantwoord.

Moet die akkuraatheid van int gelyk wees aan unsigned int, jy sal bevorder word na'n onderteken int en jy sal kry die waarde -4444 van die uitdrukking (u+i).Nou, moet u en ek het ander waardes, wat jy kan kry oorloop en ongedefinieerde gedrag nie, maar met dié presiese getalle jy sal kry -4444 [1].Hierdie waarde sal hê tipe int.Maar jy probeer om te slaan dat die waarde in'n ongetekende int so dit sal dan gegooi word om'n ongetekende int en die waarde wat die gevolg sal eindig met sou wees (UINT_MAX+1) - 4444.

Moet die akkuraatheid van die ongetekende int groter wees as dié van'n int, die ondertekende int sal bevorder word tot'n ongetekende int opbrengs van die waarde (UINT_MAX+1) - 5678 wat sal bygevoeg word om die ander unsigned int 1234.Moet u en ek het ander waardes, wat maak die uitdrukking val buite die omvang {0..UINT_MAX} die waarde (UINT_MAX+1) sal óf bygevoeg of afgetrek totdat die resultaat NIE val binne die omvang {0..UINT_MAX) en geen ongedefinieerde gedrag sal plaasvind.

Wat is presisie?

Heelgetalle het padding stukkies, teken stukkies, en waarde stukkies.Ongetekende heelgetalle nie'n teken bietjie natuurlik.Ongetekende kar is verder gewaarborg om nie padding stukkies.Die aantal waardes stukkies'n heelgetal het is hoe baie presisie dit het.

[Gotchas]

Die makro sizeof makro alleen kan nie gebruik word om te bepaal presisie van'n heelgetal as padding stukkies teenwoordig is.En die grootte van'n byte hoef nie te wees'n oktet (agt stukkies), soos gedefinieer deur C99.

[1] Die oorloop kan voorkom by een van die twee punte.Óf voor die byvoeging (tydens die bevordering) - wanneer jy'n ongetekende int wat is te groot om te pas in'n int.Die oorloop kan ook voorkom na die toevoeging selfs as die ongetekende int was binne die omvang van'n int, na die toevoeging van die resultaat kan nog steeds oorloop.


Op'n verwante noot, ek is'n onlangse gegradueerde student probeer om werk te kry ;)

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top