C++

Conversioni standard C++

Conversioni standard C++
Esistono due tipi di entità in C++, i tipi fondamentali e i tipi composti. I tipi fondamentali sono i tipi scalari. I tipi composti sono il resto dei tipi di entità. La conversione può avvenire da un tipo di entità a un altro tipo appropriato. Considera il seguente programma:

#includere
#includere
usando lo spazio dei nomi std;
intero principale()

int rt1 = sqrt(5);
int rt2 = sqrt(8);
cout<restituisce 0;

L'uscita è 2, 2, il che significa che il programma ha restituito la radice quadrata di 5 come 2 e la radice quadrata di 8 anche come 2. Quindi, le prime due affermazioni in principale() funzione hanno pavimentato le risposte della radice quadrata di 5 e della radice quadrata di 8. Questo articolo non tratta la pavimentazione o il soffitto in Do++. Piuttosto, questo articolo discute la conversione di un tipo C++ in un altro tipo C++ appropriato; indicando qualsiasi approssimazione nel valore apportato, perdita di precisione o vincolo aggiunto o rimosso. La conoscenza di base del C++ è un prerequisito per comprendere questo articolo.

Contenuto dell'articolo

  • Conversioni integrali
  • Conversioni in virgola mobile
  • Conversioni Floating-Integrale
  • Classifica delle conversioni intere
  • Promozioni integrali
  • Conversioni aritmetiche usuali
  • Promozione in virgola mobile
  • Conversioni puntatore
  • Conversioni da funzione a puntatore
  • Conversioni booleane
  • Lvalue, prvalue e xvalue
  • Xvalue
  • Conversioni da Lvalue a rvalue
  • Conversioni da array a puntatore
  • Conversioni da funzione a puntatore
  • Conversioni di materializzazione temporanea
  • Conversioni di qualificazione
  • Conclusione

Conversioni integrali

Le conversioni integrali sono conversioni intere. Gli interi senza segno includono "unsigned char", "unsigned short int", "unsigned int", "unsigned long int" e "unsigned long long int"." Gli interi con segno corrispondenti includono "signed char", "short int", "int", "long int" e "long long int"."Ogni tipo int dovrebbe essere contenuto in tanti byte quanti il ​​suo predecessore. Per la maggior parte dei sistemi, un tipo di entità può essere convertito in un tipo corrispondente senza alcun problema. Il problema si verifica durante la conversione da un tipo di intervallo più grande a un tipo di intervallo più piccolo o quando si converte un numero con segno in un numero senza segno corrispondente.

Ogni compilatore ha un valore massimo che può assumere per lo short int. Se allo short int viene assegnato un numero superiore a quel massimo, inteso per un int, il compilatore seguirà un algoritmo e restituirà un numero all'interno dell'intervallo dello short int. Se il programmatore è fortunato, il compilatore avviserà di problemi con l'utilizzo di una conversione inappropriata. La stessa spiegazione si applica alle conversioni di altri tipi int.

L'utente dovrebbe consultare la documentazione del compilatore per determinare i valori limite per ogni tipo di entità.

Se un numero short int con segno negativo deve essere convertito in un numero short int senza segno, il compilatore seguirà un algoritmo e restituirà un numero positivo all'interno dell'intervallo dello short int senza segno. Questo tipo di conversione dovrebbe essere evitato. La stessa spiegazione si applica alle conversioni di altri tipi int.

Qualsiasi numero intero, tranne 0, può essere convertito in booleano vero. 0 viene convertito in booleano falso. Il codice seguente lo illustra:

int a = -27647;
galleggiante b = 2.5;
intero c = 0;
bool a1 = a;
bool b1 = b;
bool c1 = c;
cout<cout<cout<L'uscita è:

1 per vero
1 per vero
0 per falso

Conversioni in virgola mobile

I tipi a virgola mobile includono "float", "double" e "long double."I tipi a virgola mobile non sono raggruppati in con segno e senza segno, come gli interi. Ogni tipo può avere un numero firmato o non firmato. Un tipo a virgola mobile dovrebbe avere almeno la stessa precisione del suo predecessore. Cioè, "long double" dovrebbe avere una precisione uguale o maggiore a "double" e "double" dovrebbe avere una precisione uguale o maggiore a "float"."

Ricorda che l'intervallo di un tipo a virgola mobile non è continuo; piuttosto, è a piccoli passi. Maggiore è la precisione del tipo, minori sono i passaggi e maggiore è il numero di byte per memorizzare il numero. Quindi, quando un numero a virgola mobile viene convertito da un tipo di precisione inferiore a un tipo di precisione superiore, il programmatore deve accettare un falso aumento della precisione e un possibile aumento del numero di byte per l'archiviazione del numero. Quando un numero a virgola mobile viene convertito da un tipo di precisione superiore a un tipo di precisione inferiore, il programmatore deve accettare una perdita di precisione. Se il numero di byte per l'archiviazione dei numeri deve essere ridotto, il compilatore seguirà un algoritmo e restituirà un numero come sostituto (che probabilmente non è quello che vuole il programmatore). Inoltre, tieni presente i problemi fuori portatarange.

Conversioni Floating-Integrale

Un numero in virgola mobile viene convertito in un intero troncando la parte frazionaria. Il codice seguente lo illustra:

galleggiante f = 56.953;
int io = f;
cout<L'uscita è 56. Gli intervalli per float e integer devono essere compatibili.

Quando un intero viene convertito in float, il valore visualizzato come float è lo stesso di quello digitato come intero. Tuttavia, l'equivalente float potrebbe essere il valore esatto o avere una leggera differenza frazionaria che non viene visualizzata. La ragione della differenza frazionaria è che i numeri in virgola mobile sono rappresentati nel computer in piccoli passi frazionari, quindi rappresentare esattamente l'intero sarebbe una coincidenza. Quindi, sebbene l'intero visualizzato come float sia lo stesso che è stato digitato, il display potrebbe essere un'approssimazione di ciò che è memorizzato.

Classifica delle conversioni intere

Qualsiasi tipo intero ha un rango che gli è stato assegnato. Questa classifica aiuta nella conversione. La classifica è relativa; i ranghi non sono a livelli fissi. Fatta eccezione per char e char firmato, nessun numero intero con segno non ha lo stesso rango (supponendo che char sia firmato). I tipi interi senza segno hanno la stessa classificazione dei corrispondenti tipi interi con segno. La classifica è la seguente:

  • Supponendo che char sia firmato, allora char e firmato char hanno lo stesso rango.
  • Il rango di un tipo intero con segno è maggiore del rango di un tipo intero con segno di un numero inferiore di byte di archiviazione. Quindi, il rango di Signed long long int è maggiore del rango di Signed long int, che è maggiore del rango di Signed int, che è maggiore del rango di Signed short int, che è maggiore del grado di Signed char.
  • Il rango di qualsiasi tipo intero senza segno è uguale al rango del corrispondente tipo intero con segno.
  • Il rango del carattere senza segno è uguale al rango del carattere con segno.
  • bool ha il rango minimo; il suo rango è inferiore a quello di char firmato.
  • char16_t ha lo stesso rango dello short int. char32_t ha lo stesso rango di int. Per il compilatore g++, wchar_t ha lo stesso rango di int.

Promozioni integrali

Le promozioni integrali sono promozioni intere. Non c'è motivo per cui un numero intero di meno byte non possa essere rappresentato da un numero intero di byte maggiori. Integer Promotions si occupa di tutto ciò che segue:

  • Un int corto con segno (due byte) può essere convertito in un int con segno (quattro byte). Un unsigned short int (due byte) può essere convertito in un unsigned int (quattro byte). Nota: la conversione di un short int in un long int o long long int comporta uno spreco di byte di archiviazione (posizione dell'oggetto) e uno spreco di memoria. Bool, char16_t, char32_t e wchar_t sono esentati da questa promozione (con il compilatore g++, char32_t e wchar_t hanno lo stesso numero di byte).
  • Con il compilatore g++, un tipo char16_t può essere convertito in un tipo int con segno o un tipo int senza segno; un tipo char32_t può essere convertito in un tipo int con segno o un tipo int senza segno; e un tipo wchar_t può essere convertito in un tipo int firmato o non firmato.
  • Un tipo bool può essere convertito in un tipo int. In questo caso, vero diventa 1 (quattro byte) e falso diventa 0 (quattro byte). Int può essere firmato o firmato.
  • La promozione di interi esiste anche per il tipo di enumerazione senza ambito - vedere più avanti.

Conversioni aritmetiche usuali

Considera il seguente codice:

galleggiante f = 2.5;
int io = f;
cout<Il codice viene compilato senza indicare alcun avviso o errore, dando l'output di 2, che probabilmente non è quello che ci si aspettava. = è un operatore binario perché accetta un operando sinistro e destro. Considera il seguente codice:

int i1 = 7;
int i2 = 2;
float flt = i1 / i2;
cout<L'uscita è 3, ma questo è sbagliato; doveva essere 3.5. Anche l'operatore di divisione, /, è un operatore binario.

Il C++ ha le normali conversioni aritmetiche che il programmatore deve conoscere per evitare errori di codifica. Le consuete conversioni aritmetiche sugli operatori binari sono le seguenti:

  • Se uno degli operandi è del tipo "long double", l'altro verrà convertito in long double.
  • Altrimenti, se uno degli operandi è doppio, l'altro verrà convertito in doppio.
  • Altrimenti, se uno degli operandi è float, l'altro verrà convertito in float. Nel codice sopra, il risultato di i1/i2 è ufficialmente 2; ecco perché flt è 2. Il risultato del binario, /, viene applicato come operando destro all'operatore binario, =. Quindi, il valore finale di 2 è un float (non un int).

ALTRIMENTI, LA PROMOZIONE INTEGER AVVERREBBE COME SEGUENTE:

  • Se entrambi gli operandi sono dello stesso tipo, non avviene alcuna ulteriore conversione.
  • Altrimenti, se entrambi gli operandi sono tipi interi con segno o entrambi sono tipi interi senza segno, l'operando del tipo con il rango intero inferiore verrà convertito nel tipo dell'operando con il rango superiore.
  • Altrimenti, se un operando è con segno e l'altro è senza segno, e se il tipo di operando senza segno è maggiore o uguale al rango del tipo di operando con segno, e se il valore dell'operando con segno è maggiore o uguale a zero, allora l'operando con segno verrà convertito nel tipo di operando senza segno (con l'intervallo preso in considerazione). Se l'operando con segno è negativo, il compilatore seguirà un algoritmo e restituirà un numero che potrebbe non essere accettabile per il programmatore.
  • Altrimenti, se un operando è un tipo intero con segno e l'altro è un tipo intero senza segno, e se tutti i possibili valori del tipo dell'operando con il tipo intero senza segno possono essere rappresentati dal tipo intero con segno, allora il tipo intero senza segno sarà essere convertito nel tipo dell'operando del tipo intero con segno.
  • Altrimenti, i due operandi (un char e un bool, per esempio) verrebbero convertiti nel tipo intero senza segno.

Promozione in virgola mobile

I tipi a virgola mobile includono "float", "double" e "long double."Un tipo a virgola mobile dovrebbe avere almeno la stessa precisione del suo predecessore. La promozione in virgola mobile consente la conversione da float a double o da double a long double.

Conversioni puntatore

Un puntatore di un tipo di oggetto non può essere assegnato a un puntatore di un diverso tipo di oggetto. Il seguente codice non verrà compilato:

int id = 6;
int* intPtr = &id;
idf galleggiante = 2.5;
float* floatPtr = &idf;
intPtr = floatPtr; // errore qui

Un puntatore nullo è un puntatore il cui valore di indirizzo è zero. Un puntatore null di un tipo di oggetto non può essere assegnato a un puntatore null di un diverso tipo di oggetto. Il seguente codice non verrà compilato:

int id = 6;
int* intPtr = &id;
intPtr = 0;
idf galleggiante = 2.5;
float* floatPtr = &idf;
floatPtr = 0;
intPtr = floatPtr; // errore qui

Un puntatore null const di un tipo di oggetto non può essere assegnato a un puntatore null const di un diverso tipo di oggetto. Il seguente codice non verrà compilato:

int id = 6;
int* intPtr = &id;
int* const intPC = 0;
idf galleggiante = 2.5;
float* floatPtr = &idf;
float* const floatPC = 0;
intPC = floatPC; // errore qui

A un puntatore nullo può essere assegnato un valore di indirizzo diverso per il suo tipo. Il codice seguente lo illustra:

idf galleggiante = 2.5;
float* floatPtr = 0;
floatPtr = &idf;
cout<<*floatPtr<<'\n';

L'uscita è 2.5.

Come previsto, a una costante del puntatore nullo non può essere assegnato alcun valore di indirizzo del suo tipo. Il seguente codice non verrà compilato:

idf galleggiante = 2.5;
float* const floatPC = 0;
floatPC = &idf; // errore qui

Tuttavia, una costante del puntatore nullo può essere assegnata a un puntatore ordinario, ma dello stesso tipo (è prevedibile). Il codice seguente lo illustra:

idf galleggiante = 2.5;
float* const floatPC = 0;
float* floatPter = &idf;
floatPter = floatPC; //OK
cout << floatPter << '\n';

L'uscita è 0.

Due valori del puntatore nullo dello stesso tipo confrontano (==) uguale.

Un puntatore a un tipo di oggetto può essere assegnato a un puntatore a void. Il codice seguente lo illustra:

idf galleggiante = 2.5;
float* floatPtr = &idf;
vuoto* vd;
vd = floatPtr;

Il codice viene compilato senza un avviso o un messaggio di errore.

Conversioni da funzione a puntatore

Un puntatore a una funzione che non genererebbe un'eccezione può essere assegnato a un puntatore a funzione. Il codice seguente lo illustra:

#includere
usando lo spazio dei nomi std;
void fn1() senza eccezione

cout << "with noexcept" << '\n';

vuoto fn2()

//dichiarazioni

void (*func1)() noeccetto;
void (*func2)();
intero principale()

funzione1 = &fn1;
funzione2 = &fn2;
funzione2 = &fn1;
funzione2();
restituisce 0;

L'uscita è senza eccezione.

Conversioni booleane

In C++, le entità che possono risultare false includono "zero", "puntatore nullo" e "puntatore membro nullo"."Tutte le altre entità risultano true. Il codice seguente lo illustra:

bool a = 0.0; cout << a <<'\n';
float* floatPtr = 0;
bool b = floatPtr; cout << b <<'\n';
bool c = -2.5; cout << c <<'\n';
bool d = +2.5; cout << d <<'\n';

L'uscita è:

0 //per falso
0 //per falso
1 //per vero
1 //per vero

Lvalue, prvalue e xvalue

Considera il seguente codice:

int id = 35;
int& id1 = id;
cout << id1 << '\n';

L'uscita è 35. Nel codice, id e id1 sono lvalue perché identificano una posizione (oggetto) in memoria. L'uscita 35 è un prvalue. Qualsiasi letterale, eccetto un letterale stringa, è un prvalue. Altri valori non sono così ovvi, come negli esempi che seguono. Considera il seguente codice:

int id = 62;
int* ptr = &id;
int* pter;

Ptr è un lvalue perché identifica una posizione (oggetto) in memoria. D'altra parte, pter non è un lvalue. Pter è un puntatore, ma non identifica alcuna posizione in memoria (non punta a nessun oggetto). Quindi, pter è un prvalue.

Considera il seguente codice:

vuoto fn()

//dichiarazioni

void (*func)() = &fn;
float (*functn)();

Fn() e (*func)() sono espressioni lvalue perché identificano un'entità (funzione) in memoria. D'altra parte, (*functn)() non è un'espressione lvalue. (*functn)() è un puntatore a una funzione, ma non identifica alcuna entità in memoria (non punta a nessuna funzione in memoria). Quindi, (*functn)() è un'espressione prvalue.

Ora, considera il seguente codice:

struttura S

int n;
;
S obj;

S è una classe e obj è un oggetto istanziato dalla classe. Obj identifica un oggetto in memoria. Una classe è un'unità generalizzata. Quindi, S non identifica realmente alcun oggetto in memoria. Si dice che S sia un oggetto senza nome. S è anche un'espressione di valore.

Il focus di questo articolo è sui prvalues. Prvalue significa puro rvalue.

Xvalue

Xvalue sta per Scadenza Valore. I valori temporanei sono valori in scadenza. Un lvalue può diventare un xvalue. Un prvalue può anche diventare un xvalue. Il focus di questo articolo è sui prvalues. Un xvalue è un lvalue o un riferimento rvalue senza nome la cui memoria può essere riutilizzata (di solito perché è vicino alla fine della sua durata). Considera il seguente codice che funziona:

struttura S

int n;
;
intq = S().n;

L'espressione “int q = S().n;" copia qualsiasi valore n detiene in q. S() è solo un mezzo; non è un'espressione usata regolarmente. S() è un prvalue il cui uso lo ha convertito in un xvalue.

Conversioni valore-rvalore

Considera la seguente affermazione:

int ii = 70;

70 è un prvalue (rvalue) e ii è un lvalue. Ora, considera il seguente codice:

int ii = 70;
int tt = ii;

Nella seconda affermazione, ii è nella situazione di un prvalue, quindi ii diventa un prvalue lì. In altre parole, il compilatore converte implicitamente ii in un prvalue. Cioè, quando viene utilizzato un lvalue in una situazione in cui l'implementazione si aspetta un prvalue, l'implementazione converte lvalue in un prvalue.

Conversioni da array a puntatore

Considera il seguente codice che funziona:

carattere* p;
char q[] = 'a', 'b', 'c';
p = &q[0];
++p;
cout<<*p<<'\n';

L'uscita è b. La prima affermazione è un'espressione ed è un puntatore a un carattere. Ma a quale personaggio sta puntando l'affermazione?? - Nessun carattere. Quindi, è un prvalue e non un lvalue. La seconda istruzione è un array in cui q[] è un'espressione lvalue. La terza istruzione trasforma il prvalue, p, in un'espressione lvalue, che punta al primo elemento dell'array.

Conversioni da funzione a puntatore

Considera il seguente programma:

#includere
usando lo spazio dei nomi std;
void (*func)();
vuoto fn()

//dichiarazioni

intero principale()

funzione = &fn;
restituisce 0;

L'espressione "void (*func)();" è un puntatore a una funzione. Ma a quale funzione punta l'espressione?? - Nessuna funzione. Quindi, è un prvalue e non un lvalue. Fn() è una definizione di funzione, dove fn è un'espressione lvalue. In main(), “func = &fn;” trasforma il prvalue, func, in un'espressione lvalue che punta alla funzione, fn().

Conversioni di materializzazione temporanea

In C++, un prvalue può essere convertito in un xvalue dello stesso tipo. Il codice seguente lo illustra:

struttura S

int n;
;
intq = S().n;

Qui, il prvalue, S(), è stato convertito in un xvalue. Come valore x, non durerebbe a lungo - vedi maggiori spiegazioni sopra.

Conversioni di qualificazione

Un tipo qualificato cv è un tipo qualificato dalla parola riservata "const" e/o dalla parola riservata "volatile"."

Anche la qualifica Cv è classificata. Nessuna qualifica cv è inferiore alla qualifica "const", che è inferiore alla qualifica "const volatile". Nessuna qualifica cv è inferiore alla qualifica "volatile", che è inferiore alla qualifica "const volatile". Quindi, ci sono due flussi di classifica di qualificazione. Un tipo può essere più qualificato cv di un altro.

Un tipo prvalue con cv qualificato più basso può essere convertito in un tipo prvalue con cv più qualificato. Entrambi i tipi dovrebbero essere pointer-to-cv.

Conclusione

Le entità C++ possono essere convertite da un tipo a un tipo correlato in modo implicito o esplicito. Tuttavia, il programmatore deve capire cosa può essere convertito e cosa non può essere convertito e in quale forma. La conversione può avvenire nei seguenti domini: conversioni integrali, conversioni in virgola mobile, conversioni integrali mobili, conversioni aritmetiche usuali, conversioni puntatore, conversioni da funzione a puntatore, conversioni booleane, conversioni da valore L a valore, conversioni da matrice a puntatore , Conversioni da funzione a puntatore, Conversioni di materializzazione temporanea e Conversioni di qualificazione.

Come modificare le impostazioni del mouse e del touchpad utilizzando Xinput in Linux
La maggior parte delle distribuzioni Linux viene fornita con la libreria "libinput" per impostazione predefinita per gestire gli eventi di input su un...
Rimappa i pulsanti del mouse in modo diverso per software diversi con X-Mouse Button Control
Forse hai bisogno di uno strumento che possa cambiare il controllo del tuo mouse con ogni applicazione che utilizzi. In questo caso, puoi provare un'a...
Recensione del mouse wireless Microsoft Sculpt Touch
Ho letto di recente del Microsoft Scolpisci il tocco mouse wireless e ho deciso di acquistarlo. Dopo averlo usato per un po', ho deciso di condividere...