Een waarschuwing – vergelijking tussen getekende en niet-ondertekende integer-expressies

Ik ben momenteel bezig met Accelerated C++en ben een probleem tegengekomen in oefening 2-3.

Een snel overzicht van het programma– het programma neemt in feite een naam aan en geeft vervolgens een begroeting weer binnen een kader van asterisken – d.w.z. Hallo! omgeven door *’s.

De oefening– In het voorbeeldprogramma gebruiken de auteurs const intom de opvulling (spaties) tussen de begroeting en de sterretjes te bepalen. Vervolgens vragen ze de lezer, als onderdeel van de oefening, om de gebruiker om input te vragen over hoe groot ze de opvulling willen hebben.

Dit lijkt allemaal eenvoudig genoeg, ik vraag de gebruiker om twee gehele getallen (int) en sla deze op en verander het programma om deze gehele getallen te gebruiken, waarbij ik degene die door de auteur zijn gebruikt verwijderd bij het compileren hoewel ik de volgende waarschuwing krijg;

Oefening2-3.cpp:46: waarschuwing: vergelijking tussen getekende en niet-ondertekende integer-expressies

Na wat onderzoek lijkt het erop dat de code een van de bovenstaande gehele getallen (int) probeert te vergelijken met een string::size_type, wat prima is. Maar ik vroeg me af: betekent dit dat ik een van de gehele getallen moet veranderen in unsigned int? Is het belangrijk om expliciet aan te geven of mijn gehele getallen al dan niet ondertekend zijn?

cout << "Please enter the size of the frame between top and bottom you would like ";
 int padtopbottom;
 cin >> padtopbottom;
 cout << "Please enter size of the frame from each side you would like: ";
 unsigned int padsides; 
 cin >> padsides;
 string::size_type c = 0; // definition of c in the program
 if (r == padtopbottom + 1 && c == padsides + 1) { // where the error occurs

Hierboven zijn de relevante stukjes code, de cis van het type string::size_typeOmdat we niet weten hoe lang de begroeting is – maar waarom Krijg nu dit probleem, wanneer de code van de auteur niet het probleem heeft ontvangen bij gebruik van const int? Daarnaast – voor iedereen die mogelijk Accelerated C++ heeft voltooid – zal dit later in het boek worden uitgelegd?

Ik ben op Linux Mint met G ++ via Gany, als dat helpt of een verschil maakt (zoals ik lees, kan het bij het bepalen van wat string::size_typeis).


Antwoord 1, Autoriteit 100%

Het is meestal een goed idee om variabelen te declareren als unsignedof size_tals ze worden vergeleken met formaten, om dit probleem te voorkomen. Gebruik wanneer mogelijk het exacte type dat u zult vergelijken met (gebruik bijvoorbeeld std::string::size_typebij het vergelijken met een std::string‘s Length) .

Compilers geven waarschuwingen over het vergelijken van gesigneerde en niet-ondertekende typen omdat de reeksen van ondertekende en niet-ondertekende inten anders zijn, en wanneer ze met elkaar worden vergeleken, kunnen de resultaten verrassend zijn. Als u een dergelijke vergelijking moet maken, moet u expliciet een van de waarden omzetten naar een type dat compatibel is met de andere, misschien na het controleren om ervoor te zorgen dat de conversie geldig is. Bijvoorbeeld:

unsigned u = GetSomeUnsignedValue();
int i = GetSomeSignedValue();
if (i >= 0)
{
    // i is nonnegative, so it is safe to cast to unsigned value
    if ((unsigned)i >= u)
        iIsGreaterThanOrEqualToU();
    else
        iIsLessThanU();
}
else
{
    iIsNegative();
}

Antwoord 2, Autoriteit 8%

Ik had gisteren exact hetzelfde probleem bij het doorwerken van probleem 2-3 in Accelerated C++. De sleutel is om alle variabelen die u gaat vergelijken (met behulp van Booleaanse operatoren) te wijzigen in compatibele typen. In dit geval betekent dat string::size_type(of unsigned int, maar aangezien dit voorbeeld de eerste gebruikt, zal ik me daaraan houden, ook al zijn de twee technisch compatibel).

Merk op dat ze in hun oorspronkelijke code precies dit deden voor de c-teller (pagina 30 in paragraaf 2.5 van het boek), zoals je terecht opmerkte.

Wat dit voorbeeld ingewikkelder maakt, is dat de verschillende opvulvariabelen (padsides en padtopbottom), evenals alle tellers, ookmoeten worden gewijzigd in string::size_type.

Om bij uw voorbeeld te komen: de code die u heeft gepost, ziet er uiteindelijk als volgt uit:

cout << "Please enter the size of the frame between top and bottom";
string::size_type padtopbottom;
cin >> padtopbottom;
cout << "Please enter size of the frame from each side you would like: ";
string::size_type padsides; 
cin >> padsides;
string::size_type c = 0; // definition of c in the program
if (r == padtopbottom + 1 && c == padsides + 1) { // where the error no longer occurs

Merk op dat u in de vorige voorwaarde de fout zou krijgen als u variabele r niet zou initialiseren als een string::size_typein de for-lus. Dus je moet de for-lus initialiseren met zoiets als:

   for (string::size_type r=0; r!=rows; ++r)   //If r and rows are string::size_type, no error!

Dus, in principe, zodra u een string::size_typevariabele in de mix introduceert, op elk moment dat u een Booleaanse bediening op dat artikel wilt uitvoeren, moeten alle operanden er een compatibel type voor hebben compileren zonder waarschuwingen.


Antwoord 3, Autoriteit 5%

Het belangrijke verschil tussen ondertekende en niet-ondertekende inten
is de interpretatie van het laatste bit. Het laatste bit
In ondertekende typen vertegenwoordigen het teken van het nummer, wat betekent:
b.v:

0001 is 1 gesigneerd en niet-ondertekend
1001 is -1 ondertekend en 9 niet-ondertekend

(Ik vermeed het volledige aanvullingsprobleem voor de duidelijkheid van de uitleg!
Dit is niet precies hoe Ints worden weergegeven in het geheugen!)

Je kunt je voorstellen dat het een verschil maakt om te weten of je het vergelijkt
met -1 of met +9. In veel gevallen zijn programmeurs gewoon te lui
om tellende inten te verklaren als niet-ondertekend (opgeblazen aan de voor loopkop F.I.)
Het is meestal geen probleem omdat je met Ints moet tellen tot 2 ^ 31
totdat je bitje je bijt. Daarom is het slechts een waarschuwing.
Omdat we te lui zijn om ‘niet-ondertekend’ te schrijven in plaats van ‘int’.


Antwoord 4, Autoriteit 4%

Bij de extreme reeksen kan een niet-ondertekende int groter worden dan een int.
Daarom genereert de compiler een waarschuwing. Als u er zeker van bent dat dit geen probleem is, voel u dan vrij om de typen naar hetzelfde type te werpen, zodat de waarschuwing verdwijnt (gebruik C++ Cast zodat ze gemakkelijk te zien zijn).

Maak alternatief de variabelen hetzelfde type om de compiler te stoppen van het klagen.
Ik bedoel, is het mogelijk om een ​​negatieve opvulling te hebben? Zo ja, houd het dan als een int. Anders zou u waarschijnlijk niet-ondertekende INT moeten gebruiken en de stroom de situaties vangt waar de gebruikerstypen in een negatief getal zijn.


Antwoord 5

Het primaire probleem is dat onderliggende hardware, de CPU alleen instructies heeft om twee ondertekende waarden te vergelijken of twee niet-ondertekende waarden te vergelijken. Als u de niet-ondertekende vergelijkingsinstructie een ondertekende, negatieve waarde passeert, zal deze het als een groot positief aantal behandelen. Dus, -1, het bitpatroon met alle bits aan (TwoS-complement), wordt de maximale niet-ondertekende waarde voor hetzelfde aantal bits.

8-bits: -1 ondertekend is dezelfde bits als 255 niet-ondertekend
16-bits: -1 ondertekend is dezelfde bits als 65535 niet-ondertekend
enz.

Dus, als u de volgende code hebt:

int fd;
fd = open( .... );
int cnt;
SomeType buf;
cnt = read( fd, &buf, sizeof(buf) );
if( cnt < sizeof(buf) ) {
    perror("read error");
}

U zult merken dat als de lees (2) oproep mislukt vanwege de bestandsdescriptor die ongeldig wordt (of een andere fout), die CNT is ingesteld op -1. Bij vergelijking met SiAtOF (BUF), is de niet-ondertekende waarde, de IF () -verklaring onjuist omdat 0xFFFFFFFF niet minder is dan maat () Sommige (redelijke, niet verzonnen als maximale grootte) Gegevensstructuur.

Dus moet u het bovenstaande schrijven als, om de ondertekende / niet-ondertekende waarschuwing te verwijderen als:

if( cnt < 0 || (size_t)cnt < sizeof(buf) ) {
    perror("read error");
}

Dit spreekt gewoon luid op de problemen.

1.  Introduction of size_t and other datatypes was crafted to mostly work, 
    not engineered, with language changes, to be explicitly robust and 
    fool proof.
2.  Overall, C/C++ data types should just be signed, as Java correctly
    implemented.

Als u waarden heeft die zo groot zijn dat u geen ondertekend waardetype kunt vinden dat werkt, gebruikt u een te kleine processor of een te grote hoeveelheid waarden in de taal van uw keuze. Als, zoals bij geld, elk cijfer telt, zijn er systemen die je in de meeste talen kunt gebruiken die je oneindig veel precisie geven. C/C++ doet dit gewoon niet goed, en je moet heel expliciet zijn over alles rond typen, zoals vermeld in veel van de andere antwoorden hier.


Antwoord 6

of gebruik deze headerbibliotheeken schrijf:

// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))

en geef niet om ondertekende/niet-ondertekende of verschillende formaten

Other episodes