Domanda

Al momento sto lavorando con Accelerated C ++ e hanno incontrato un problema in esercizio 2-3.

Una rapida panoramica del programma - il programma è quasi esclusivamente un nome, quindi visualizza un saluto all'interno di una cornice di asterischi - vale a dire Ciao! circondato incorniciato da * 's.

L'esercizio - Nel programma di esempio, gli autori usano const int per determinare l'imbottitura (spazi vuoti) tra il saluto e gli asterischi. Hanno poi chiedere al lettore, come parte dell'esercizio, per chiedere all'utente per l'input su come grande che vogliono l'imbottitura sia.

Tutto questo sembra abbastanza facile, vado avanti chiedere all'utente per due interi (int) e memorizzarli e cambiare il programma di utilizzare questi numeri interi, togliendo quelle usate dall'autore, quando si compila anche se ottengo il seguente avvertimento;

  

Exercise2-3.cpp: 46: avvertimento: Confronto tra il sottoscritto e le espressioni Intero senza segno

Dopo alcune ricerche sembra essere perché il codice tentativi di confrontare uno dei numeri interi di cui sopra (int) ad una string::size_type, che va bene. Ma mi chiedevo - significa dovrei cambiare uno dei numeri interi a unsigned int? E 'importante esplicitamente dichiarare se i miei numeri interi sono con o senza segno?

 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

Sopra sono i bit rilevanti di codice, il c è di tipo string::size_type perché non sappiamo per quanto tempo il saluto potrebbe essere - ma il motivo per cui faccio ad avere questo problema ora, quando il codice dell'autore non ha ottenuto il problema quando si utilizza const int? In aggiunta - a tutti coloro che possono aver completato Accelerated C ++ -? Questo sarà spiegato più avanti nel libro

Sono su Linux Mint con g ++ tramite Geany, se questo aiuta o fa la differenza (come ho letto che poteva nel determinare ciò che è string::size_type).

È stato utile?

Soluzione

Di solito è una buona idea per le variabili dichiarare come unsigned o size_t se saranno confrontati con le dimensioni, per evitare questo problema. Se possibile, utilizzare il tipo esatto vi sarà confrontando contro (per esempio, l'uso std::string::size_type quando si confrontano con la lunghezza di un std::string).

I compilatori dare avvertimenti sul confronto firmato e tipi senza segno, perché gli intervalli di interi con e senza segno sono diversi, e quando si sono confrontati tra loro, i risultati possono essere sorprendenti. Se si deve fare il confronto tale, è necessario convertire in modo esplicito uno dei valori a un tipo compatibile con l'altra, forse dopo aver controllato per garantire che la conversione è valida. Ad esempio:

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();
}

Altri suggerimenti

Ho avuto lo stesso problema di ieri di lavoro attraverso problemi 2-3 accelerata C ++. La chiave è quello di cambiare tutte le variabili verrà confrontando (usando operatori booleani) per tipi compatibili. In questo caso, che significa string::size_type (o unsigned int, ma poiché questo esempio utilizza il primo, io solo bastone con che, anche se i due sono tecnicamente compatibili).

Si noti che nel loro codice originale hanno fatto esattamente questo per il contatore c (pagina 30 nella sezione 2.5 del libro), come lei ha giustamente sottolineato.

Ciò che rende questo esempio più complicato è che le diverse variabili imbottitura (padsides e padtopbottom), così come tutti i contatori, i mosti di anche essere modificati in string::size_type.

Arrivare a esempio, il codice che hai postato finirebbe cercando in questo modo:

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

Si noti che al condizionale precedente, si otterrebbe l'errore se non si inizializza r variabile come un string::size_type nel ciclo for. Quindi è necessario inizializzare il ciclo for usando qualcosa come:

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

Quindi, in sostanza, una volta che si introduce una variabile string::size_type nel mix, ogni volta che si desidera eseguire un'operazione booleana su tale elemento, tutti gli operandi deve avere un tipo compatibile per la sua compilazione senza avvisi.

La differenza importante tra interi con e senza segno è l'interpretazione dell'ultimo bit. L'ultimo bit nei tipi firmati rappresentano il segno del numero, significato: per esempio:

0001 è 1 con e senza segno 1001 è -1 firmato e 9 senza segno

(I evitato l'intera questione complemento per chiarezza di spiegazione! Questo non è esattamente come interi vengono rappresentati in memoria!)

E 'possibile immaginare che fa la differenza per sapere se si confrontano con -1 o con +9. In molti casi, i programmatori sono troppo pigro dichiarare int conteggio come senza segno (gonfiore della testa per F.I. anello) Di solito non è un problema perché con interi bisogna contare fino a 2 ^ 31 fino a quando il bit di segno ti morde. Ecco perché è solo un avviso. Perché siamo troppo pigri per scrivere 'senza segno' invece di 'int'.

Alle intervalli estremi, un int non firmato può diventare più grande di un int.
Pertanto, il compilatore genera un avviso. Se si è sicuri che questo non è un problema, non esitate a lanciare i tipi allo stesso tipo in modo che lo scompare avvertimento (uso C ++ gettato in modo che siano facili da individuare).

In alternativa, rendere le variabili dello stesso tipo per fermare il compilatore di lamentarsi.
Voglio dire, è possibile avere un'imbottitura negativo? Se è così allora tenerlo come un int. In caso contrario, probabilmente si dovrebbe usare unsigned int e lasciare che il flusso di cattura le situazioni in cui l'utente digita un numero negativo.

questa libreria intestazione e scrittura:

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

e non si preoccupano dimensioni firmati / non firmati o diversi

Il problema principale è che l'hardware sottostante, la CPU, ha solo le istruzioni per confrontare due valori con segno o confrontare due valori senza segno. Se si passa l'istruzione di confronto senza segno un firmato, valore negativo, verrà trattato come un gran numero positivo. Quindi, -1, la sequenza di bit con tutti i bit su (complemento a due), diventa il valore senza segno massimo per lo stesso numero di bit.

8 bit: -1 firmato è gli stessi bit come 255 senza segno 16 bit: -1 Acceso è gli stessi bit come 65535 senza segno ecc.

Quindi, se avete il seguente codice:

int fd;
fd = open( .... );

int cnt;
SomeType buf;

cnt = read( fd, &buf, sizeof(buf) );

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

troverete che se la lettura (2) chiamata non riesce a causa della non valida descrittore di file diventando (o qualche altro errore), che cnt sarà impostato a -1. Quando si confrontano a sizeof (BUF), un valore senza segno, l'istruzione if () sarà falso perché 0xffffffff non meno è di sizeof () alcuni (ragionevole, non inventata per essere massima dimensione) struttura di dati.

In questo modo, si deve scrivere quanto sopra, se, per rimuovere l'avviso firmato / unsigned come:

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

Questo parla ad alta voce solo ai problemi.

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.

Se si dispone di valori così grande che non si può trovare un tipo di valore con segno che le opere, si sta utilizzando troppo piccolo di un processore o troppo grande di una grandezza di valori nella lingua di propria scelta. Se, come con i soldi, conta ogni cifra, ci sono sistemi per l'uso nella maggior parte delle lingue che vi fornirà infinite cifre di precisione. C / C ++ semplicemente non farlo bene, e devi essere molto espliciti su tutto intorno a tipi come detto in molte delle altre risposte qui.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top