Cosa significano esattamente "IB" e "UB"?


110

Ho visto i termini "IB" e "UB" utilizzati più volte, in particolare nel contesto di C ++. Ho provato a cercarli su Google, ma a quanto pare queste combinazioni di due lettere sono molto utili. : P

Quindi, ti chiedo ... cosa significano, quando vengono detti come se fossero una cosa negativa?


5
Se decidi di annullare le modifiche di qualcun altro, assicurati che l'ortografia, la punteggiatura e la grammatica siano perfette. Il rollback delle modifiche che rappresentano un miglioramento sostanziale rispetto al testo originale è inutile.
Robert Harvey

Risposte:


139

IB: comportamento definito dall'implementazione. Lo standard lascia che sia il particolare compilatore / piattaforma a definire il comportamento preciso, ma richiede che sia definito.

L'utilizzo del comportamento definito dall'implementazione può essere utile, ma rende il codice meno portabile.

UB: comportamento indefinito. Lo standard non specifica come dovrebbe comportarsi un programma che richiama un comportamento indefinito. Conosciuto anche come "demoni nasali" perché teoricamente potrebbe far volare i demoni fuori dal naso.

Usare un comportamento indefinito è quasi sempre una cattiva idea. Anche se a volte sembra funzionare, qualsiasi modifica all'ambiente, al compilatore o alla piattaforma può rompere in modo casuale il codice.


11
Sto ancora aspettando un demone che vola via dal naso di qualcuno a causa dell'utilizzo di un comportamento indefinito in C ++. Immagino che accadrà quando i primi compilatori saranno completamente conformi al nuovo standard C ++.
OregonGhost

4
@ OregonGhost: immagino che tu abbia ragione. L'ho visto accadere con gli unicorni un paio di volte, ma mai con i demoni.
Thomas

33
@OregonGhost: lo standard non specifica quante corna dovrebbe avere un demone.
DVK

5
@Michael Burr: preferisco "prendere fuoco". È evidentemente catastrofico, e ha almeno una vaga aria di plausibilità (l'hardware del computer a volte prende fuoco, certamente per ragioni di hardware piuttosto che di guasto del software nel caso di qualsiasi sistema su cui stai leggendo questo thread).
Steve Jessop

1
È divertente come nessuno che abbia risposto a questa domanda abbia meno reputazione di 30.000.

19

Comportamento definito dall'implementazione e comportamento non definito

Lo standard C ++ è molto specifico sugli effetti di vari costrutti, e in particolare dovresti sempre essere a conoscenza di queste categorie di problemi :

  • Un comportamento indefinito significa che non ci sono assolutamente garanzie fornite. Il codice potrebbe funzionare, oppure potrebbe incendiare il tuo disco rigido o far volare i demoni fuori dal tuo naso . Per quanto riguarda il linguaggio C ++, potrebbe succedere di tutto. In termini pratici, questo generalmente significa che hai un bug irrecuperabile. Se ciò accade, non puoi davvero fidarti di nulla della tua applicazione (perché uno degli effetti di questo comportamento indefinito potrebbe essere stato solo quello di rovinare la memoria utilizzata dal resto della tua app). Non è necessario essere coerenti, quindi eseguire il programma due volte potrebbe dare risultati diversi. Può dipendere dalle fasi lunari, dal colore della maglietta che indossi o da qualsiasi altra cosa.

  • Un comportamento non specificato significa che il programma deve fare qualcosa di sano e coerente, ma non è necessario documentarlo .

  • Il comportamento definito dall'implementazione è simile a unspecified, ma deve anche essere documentato dagli autori del compilatore. Un esempio di ciò è il risultato di a reinterpret_cast. di solito , cambia semplicemente il tipo di un puntatore, senza modificare l'indirizzo, ma la mappatura è effettivamente definita dall'implementazione, quindi un compilatore potrebbe mappare a un indirizzo completamente diverso, purché documentasse questa scelta. Un altro esempio è la dimensione di un int. Lo standard C ++ non si preoccupa se è di 2, 4 o 8 byte, ma deve essere documentato dal compilatore

Ma comune a tutti questi è che è meglio evitarli. Quando possibile, attenersi a un comportamento specificato al 100% dallo standard C ++ stesso. In questo modo, la portabilità è garantita.

Spesso devi fare affidamento anche su alcuni comportamenti definiti dall'implementazione. Potrebbe essere inevitabile, ma dovresti comunque prestarci attenzione ed essere consapevole che stai facendo affidamento su qualcosa che potrebbe cambiare tra diversi compilatori.

Il comportamento indefinito, invece, dovrebbe essere sempre evitato. In generale, dovresti semplicemente presumere che faccia esplodere il tuo programma in un modo o nell'altro.


1
UB dovrebbe essere evitato se ti interessa la portabilità . Una particolare implementazione può definire cosa accade per un comportamento specifico non definito e in alcuni casi (specialmente driver di dispositivo e sistemi embedded più piccoli) è necessario utilizzare queste cose.
Jerry Coffin

3
@ Jerry: No, UB dovrebbe essere evitato se è del tutto indefinito . Se la piattaforma / implementazione / runtime / compilatore fornisce ulteriori garanzie, allora puoi fare affidamento sul comportamento e perdere la portabilità. Ma poi non è più così indefinito ... La maggior parte delle volte, però, non hai tali garanzie, e undefined è semplicemente indefinito e dovrebbe essere evitato a tutti i costi.
jalf

"coerente" potrebbe essere una descrizione fuorviante di un comportamento non specificato. Deve essere coerente con il contesto generale dell'operazione, ad esempio se un'espressione ha un "valore non specificato", il risultato deve essere un valore, se lo si memorizza, il valore memorizzato deve quindi essere confrontato uguale a se stesso e così via. Ma i risultati non specificati non devono essere coerenti nel tempo (stesso output per lo stesso input se lo si esegue di nuovo) o addirittura deterministici.
Steve Jessop

"non è più così indefinito" - è esattamente indefinito dallo standard , e UB è un significato abbreviato non definito dallo standard. Nel tuo esempio è definito dall'implementazione. Del resto puoi fare affidamento su un comportamento che non è definito dallo standard o dall'implementazione, se hai controllato il codice dell'oggetto e non prevedi di ricompilarlo mai più ;-)
Steve Jessop

"deve da allora in poi confrontare uguale a se stesso". Hmm, a meno che non sia un NaN. In ogni caso, deve avere qualsiasi comportamento richiesto dal suo tipo.
Steve Jessop

8
  • IB: è un comportamento definito dall'implementazione - il compilatore deve documentare ciò che fa. L'esecuzione di >>un'operazione su un valore negativo è un esempio.

  • UB: comportamento indefinito: il compilatore può fare qualsiasi cosa, incluso semplicemente bloccarsi o dare risultati imprevedibili. La dereferenziazione di un puntatore nullo rientra in questa categoria, ma anche cose più sottili come l'aritmetica del puntatore che non rientra nei limiti di un oggetto array.

Un altro termine correlato è "comportamento non specificato". Questo è un po 'tra i comportamenti definiti dall'implementazione e quelli indefiniti. per un comportamento non specificato, il compilatore deve fare qualcosa secondo lo standard, ma esattamente quali scelte lo standard fornisce dipende dal compilatore e non è necessario che sia definito (o addirittura coerente). Cose come l'ordine di valutazione delle sottoespressioni rientrano in questa categoria. Il compilatore può eseguirle nell'ordine che preferisce e potrebbe farlo in modo diverso in build diverse o anche in esecuzioni diverse della stessa build (improbabile, ma consentito).


4

La versione breve:

Comportamento definito dall'implementazione (IB): programmato correttamente ma indeterminato *

Comportamento indefinito (UB): programmato in modo errato (ovvero un bug !)

*) "indeterminato" per quanto riguarda lo standard linguistico, sarà ovviamente determinato su qualunque piattaforma fissa.


Se lo standard indica che un'azione richiama il comportamento definito dall'implementazione, le implementazioni sono necessarie per specificare un comportamento coerente risultante da tale azione. Sfortunatamente, non esiste una categoria di comportamento per cui sarebbe richiesta un'implementazione per specificare le possibili conseguenze, ma non sarebbe richiesta che nessuna conseguenza particolare si verifichi in modo coerente.
supercat

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.