Conversioni standard C ++

Conversioni standard C ++
Esistono due tipi di entità in C ++, i tipi fondamentali e i tipi di 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: #include
#includere
Utilizzo dello spazio dei nomi std;
int main ()

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

L'output è 2, 2, 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 dichiarazioni in principale() La funzione ha piazzato le risposte della radice quadrata di 5 e la radice quadrata di 8. Questo articolo non discute di pavimenti o soffitto in C++. Piuttosto, questo articolo discute la conversione di un tipo C ++ in un altro tipo C ++ appropriato; indicando qualsiasi approssimazione in valore effettuato, perdita di precisione o vincolo aggiunto o rimosso. La conoscenza di base di C ++ è un prerequisito per comprendere questo articolo.

Contenuto dell'articolo

  • Conversioni integrali
  • Conversioni a punta mobile
  • Conversioni fluttuanti
  • Classifica di conversione interi
  • Promozioni integrali
  • Conversioni aritmetiche solite
  • Promozione a punta mobile
  • Conversioni di puntatore
  • Funzione a conversioni di punta
  • Conversioni booleane
  • LVALUE, PRVALUE E XVALUE
  • XValue
  • Conversioni da lValue-to-ralue
  • Conversioni di array-to-pointer
  • Conversioni da funzione a pointer
  • Conversioni di materializzazione temporanea
  • Conversioni di qualificazione
  • Conclusione

Conversioni integrali

Le conversioni integrali sono conversioni interi. I numeri interi non firmati includono "Carbone senza segno", "Short Int non firmato", "Insigned Int", "Unsigned Long Int" e "Unsigned Long Long Int."I numeri interi firmati corrispondenti includono" Char firmato "," Short int "," int "," long int "e" long long int."Ogni tipo int dovrebbe essere tenuto in tanti byte quanto 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 in un tipo di intervallo più piccolo o quando si converte un numero firmato in un numero non firmato corrispondente.

Ogni compilatore ha un valore massimo che può essere necessario per il breve int. Se un numero superiore a quel. Se il programmatore è fortunato, il compilatore avvertirà di problemi con 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 limitanti per ciascun tipo di entità.

Se un numero INT a breve firmato negativo deve essere convertito in un numero INT breve non firmato, il compilatore seguirà un po 'di algoritmo e restituirà un numero positivo all'interno dell'intervallo del breve int non firmato. 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 true booleano. 0 viene convertito in falso booleano. Il seguente codice illustra questo:

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

1
1
0

1 significa vero e 0 significa falso nell'output

Conversioni a punta mobile

I tipi di punto mobile includono "galleggiante", "doppio" e "lungo doppio."I tipi di punto mobile non sono raggruppati in firmati e non firmati, come numeri interi. Ogni tipo può avere un numero firmato o non firmato. Un tipo a punto mobile dovrebbe avere almeno la stessa precisione del suo predecessore. Cioè, "lungo doppio" dovrebbe avere una precisione uguale o maggiore a "doppio" e "doppio" dovrebbe avere una precisione uguale o maggiore per "galleggiare."

Ricorda che l'intervallo di un tipo a punto mobile non è continuo; Piuttosto, è in piccoli gradini. Maggiore è la precisione del tipo, minori sono i passaggi e maggiore è il numero di byte per archiviare il numero. Quindi, quando un numero di punto mobile viene convertito da un tipo di precisione inferiore a un tipo di precisione più elevato, il programmatore deve accettare un falso aumento della precisione e un possibile aumento del numero di byte per il numero di archiviazione. Quando un numero di punto mobile viene convertito da un tipo di precisione più elevato a un tipo di precisione inferiore, il programmatore deve accettare una perdita di precisione. Se il numero di byte per il numero di archiviazione deve essere ridotto, il compilatore seguirà un po 'di algoritmo e restituirà un numero come sostituto (che probabilmente non è ciò che il programmatore vuole). Inoltre, tieni presente problemi fuori portata.

Conversioni fluttuanti

Un numero di punto mobile viene convertito in un numero intero troncando la parte frazionaria. Il seguente codice illustra questo:

float f = 56.953;
int i = f;
cout<L'output è 56. Gli intervalli per il galleggiante e il numero intero devono essere compatibili.

Quando un intero viene convertito in un galleggiante, il valore visualizzato come galleggiante è lo stesso che è stato digitato come un numero intero. Tuttavia, l'equivalente del galleggiante potrebbe essere il valore esatto o avere una leggera differenza frazionaria che non viene visualizzata. Il motivo della differenza frazionaria è che i numeri a punto mobile sono rappresentati nel computer in piccole fasi frazionarie, e quindi rappresentare esattamente l'intero sarebbe una coincidenza. Quindi, sebbene l'intero visualizzato come un galleggiante sia lo stesso di digitazione, il display può essere un'approssimazione di ciò che è memorizzato.

Classifica di conversione interi

Qualsiasi tipo di intero ha un grado che è stato dato. Questa classifica aiuti nella conversione. La classifica è relativa; I ranghi non sono a livelli fissi. Tranne Char e firmato Char, non ci sono due numeri interi firmati hanno lo stesso rango (supponendo che Char sia firmato). I tipi di interi non firmati hanno la stessa classifica dei corrispondenti tipi interi firmati. La classifica è la seguente:

  • Supponendo che Char sia firmato, quindi Char e Firmato Char abbiano lo stesso rango.
  • Il grado di tipo intero firmato è maggiore del rango di un tipo intero firmato di un numero inferiore di byte di archiviazione. Quindi, il rango di Long Int Long firmata è maggiore del grado di INT Long firmata, che è maggiore del rango di INT firmato, che è maggiore del rango di Short Int firmato, che è maggiore del grado di caratteri firmati.
  • Il grado di qualsiasi tipo di intero non firmato è uguale al grado del corrispondente tipo intero firmato.
  • Il grado di carattere non firmato è uguale al grado di char firmato.
  • Bool ha il minimo grado; Il suo rango è inferiore a quello di Chard Char.
  • char16_t ha lo stesso rango del breve int. char32_t ha lo stesso rango dell'int. Per il compilatore G ++, WCHAR_T ha lo stesso rango dell'INT.

Promozioni integrali

Le promozioni integrali sono promozioni interi. Non vi è alcun motivo per cui un numero intero di meno byte non possa essere rappresentato da un numero intero di byte più grandi. Le promozioni Integer si occupa di tutto ciò che segue:

  • Un breve INT (due byte) firmato può essere convertito in un INT firmato (quattro byte). Un corto non firmato (due byte) può essere convertito in un int non firmato (quattro byte). NOTA: convertire un breve INT in un INT lungo o un lungo int lungo porta a uno spreco di byte di stoccaggio (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 firmato o in un tipo INT non firmato; Un tipo Char32_T può essere convertito in un tipo INT firmato o un tipo INT non firmato; e un tipo WCHAR_T può essere convertito in un tipo Int firmato o non firmato.
  • Un tipo di bool può essere convertito in un tipo int. In questo caso, True diventa 1 (quattro byte) e false diventa 0 (quattro byte). INT può essere firmato o firmato.
  • La promozione interi esiste anche per il tipo di enumerazione non copita - vedi più tardi.

Conversioni aritmetiche solite

Considera il seguente codice:

fluttuare f = 2.5;
int i = f;
cout<Il codice si compila senza indicare alcun avviso o errore, fornendo l'output di 2, che probabilmente non è quello che ci si aspettava. = è un operatore binario perché prende un operando sinistro e destro. Considera il seguente codice:

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

C ++ ha normali conversioni aritmetiche che il programmatore deve sapere per evitare errori nella codifica. Le solite conversioni aritmetiche sugli operatori binari sono le seguenti:

  • Se uno dei due operand è del tipo "lungo doppio", l'altro verrà convertito in un lungo doppio.
  • Altrimenti, se uno dei due operand è doppio, l'altro verrà convertito in doppio.
  • Altrimenti, se uno dei due operand è galleggiante, l'altro verrà convertito in galleggiante. Nel codice sopra, il risultato di I1/I2 è ufficialmente 2; Ecco perché FLT è 2. Il risultato del binario, /, viene applicato come operando giusto all'operatore binario, =. Quindi, il valore finale di 2 è un galleggiante (non un int).

Altrimenti, la promozione intera si svolgerà come segue:

  • Se entrambi gli operandi sono dello stesso tipo, allora non ha ulteriori conversioni.
  • Altrimenti, se entrambi gli operandi sono firmati tipi interi o entrambi sono tipi di interi non firmati, allora l'operando del tipo con il rango intero inferiore verrà convertito nel tipo di operando con il rango più alto.
  • Altrimenti, se un operando è firmato e l'altro non è firmato e se il tipo di operando non firmato è maggiore o uguale al rango del tipo di operando firmato e se il valore dell'operando firmato è maggiore o uguale a zero, allora L'operando firmato verrà convertito nel tipo di operando non firmato (con intervallo preso in considerazione). Se l'operando firmato è 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 firmato e l'altro è un tipo intero non firmato e se tutti i possibili valori del tipo di operando con il tipo intero non firmato possono essere rappresentati dal tipo intero firmato, allora il tipo intero non firmato essere convertito nel tipo di operando del tipo intero firmato.
  • Altrimenti, i due operandi (un carbone e un bool, per esempio) sarebbero convertiti in tipo intero non firmato.

Promozione a punta mobile

I tipi di punto mobile includono "galleggiante", "doppio" e "lungo doppio."Un tipo a punto mobile dovrebbe avere almeno la stessa precisione del suo predecessore. La promozione a punta mobile consente la conversione dal galleggiante al doppio o dal doppio a doppio lungo.

Conversioni di puntatore

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

int id = 6;
int* intptr = &id;
float idf = 2.5;
float* floatptr = &idf;
intptr = floatptr; // Errore qui

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

int id = 6;
int* intptr = &id;
intptr = 0;
float idf = 2.5;
float* floatptr = &idf;
floatptr = 0;
intptr = floatptr; // Errore qui

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

int id = 6;
int* intptr = &id;
int* const intpc = 0;
float idf = 2.5;
float* floatptr = &idf;
float* const floatpc = 0;
intpc = floatpc; // Errore qui

Un puntatore null può essere assegnato un valore di indirizzo diverso per il suo tipo. Il seguente codice illustra questo:

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

L'output è 2.5.

Come previsto, una costante di punta nullo non può essere assegnato alcun valore dell'indirizzo del suo tipo. Il seguente codice non si compilerà:

float idf = 2.5;
float* const floatpc = 0;
floatpc = &idf; // Errore qui

Tuttavia, è possibile assegnare una costante di puntatore nullo a un normale puntatore, ma dello stesso tipo (questo è prevedibile). Il seguente codice illustra questo:

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

L'output è 0.

Due valori di puntatore null dello stesso tipo confronta (==) uguali.

Un puntatore a un tipo di oggetto può essere assegnato a un puntatore da vuoto. Il seguente codice illustra questo:

float idf = 2.5;
float* floatptr = &idf;
void* vd;
vd = floatptr;

Il codice si compila senza un avviso o un messaggio di errore.

Funzione a conversioni di punta

Un puntatore a una funzione che non lancerebbe un'eccezione può essere assegnato a un puntatore per funzionare. Il seguente codice illustra questo:

#includere
Utilizzo dello spazio dei nomi std;
void fn1 () noexcept

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

void fn2 ()

// affermazioni

void (*func1) () noxcept;
void (*func2) ();
int main ()

func1 = &fn1;
func2 = &fn2;
func2 = &fn1;
func2 ();
restituzione 0;

L'output è con noxcept.

Conversioni booleane

In C ++, le entità che possono causare false includono "zero", "puntatore null" e "puntatore membro null."Tutte le altre entità si traducono in vera. Il seguente codice illustra questo:

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'output è:

0 // per false
0 // per false
1 // per vero
1 // per vero

LVALUE, PRVALUE E XVALUE

Considera il seguente codice:

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

L'output è 35. Nel codice, ID e ID1 sono LValues ​​perché identificano una posizione (oggetto) in memoria. L'output 35 è un prvalue. Qualsiasi letterale, tranne una corda letterale, è un prvalue. Altri prvalori non sono così evidenti, 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:

void fn ()

// affermazioni

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

Fn () e (*func) () sono espressioni LValue perché identificano un'entità (funzione) nella memoria. D'altra parte, (*functn) () non è un'espressione di 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 nessun oggetto in memoria. Si dice che S sia un oggetto senza nome. S è anche un'espressione prvalue.

Il focus di questo articolo è sui prvalori. Prvalue significa puro rValue.

XValue

XValue sta per un valore in scadenza. I valori temporanei stanno scaduti valori. Un lValue può diventare un XValue. Un prvalue può anche diventare un XValue. Il focus di questo articolo è sui prvalori. Un XValue è un LVALUE o un riferimento RValue senza nome il cui spazio di archiviazione può essere riutilizzato (di solito perché è vicino alla fine della sua vita). Considera il seguente codice che funziona:

Struttura s

int n;
;
int q = s ().N;

L'espressione “int q = s ().N;" copie qualunque valore n mantiene a q. S () è solo un mezzo; Non è un'espressione regolarmente usata. S () è un prvalue il cui uso lo ha convertito in un XVALUE.

Conversioni da lValue-to-ralue

Considera la seguente dichiarazione:

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 II in un prvalue implicitamente. Cioè, quando viene utilizzato un LVALUE in una situazione in cui l'implementazione si aspetta un punto.

Conversioni di array-to-pointer

Considera il seguente codice che funziona:

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

L'output è B. La prima affermazione è un'espressione ed è un puntatore a un personaggio. Ma a quale personaggio è l'affermazione che punta? - Nessun carattere. Quindi, è un prvalue e non un lValue. La seconda affermazione è un array in cui Q [] è un'espressione di LValue. La terza affermazione trasforma il prvalue, p, in un'espressione di lValue, che indica il primo elemento dell'array.

Conversioni da funzione a pointer

Considera il seguente programma:

#includere
Utilizzo dello spazio dei nomi std;
void (*func) ();
void fn ()

// affermazioni

int main ()

func = &fn;
restituzione 0;

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

Conversioni di materializzazione temporanea

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

Struttura s

int n;
;
int q = s ().N;

Qui, il prvalue, s (), è stato convertito in un XValue. Come XValue, non durerebbe a lungo - vedi più spiegazioni sopra.

Conversioni di qualificazione

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

La qualificazione CV è anche classificata. Nessuna qualificazione CV è inferiore alla qualifica "const", che è inferiore alla qualifica "const volatile". Nessuna qualificazione CV è inferiore alla qualifica "volatile", che è inferiore alla qualificazione "const volatile". Quindi, ci sono due flussi di classifica delle qualifiche. Un tipo può essere più qualificato con un altro.

Un tipo di qualificato CV inferiore può essere convertito in un tipo di prvalue qualificato più CV. Entrambi i tipi dovrebbero essere puntatore a CV.

Conclusione

Le entità C ++ possono essere convertite da un tipo in un tipo correlato implicitamente o esplicitamente. 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 a punta mobile, conversioni integrali galleggianti, conversioni aritmetiche usuali, conversioni di punta , Conversioni da funzione a pointer, conversioni di materializzazione temporanea e conversioni di qualificazione.