2010-03-24 17 views
14

Lo standard dice che il dereferenziamento del puntatore nullo porta a un comportamento non definito. Ma cos'è "il puntatore nullo"? Nel codice seguente, quello che noi chiamiamo "il puntatore nullo":Quale di questi creerà un puntatore nullo?

struct X 
{ 
    static X* get() { return reinterpret_cast<X*>(1); } 
    void f() { } 
}; 

int main() 
{ 
    X* x = 0; 
    (*x).f(); // the null pointer? (1) 

    x = X::get(); 
    (*x).f(); // the null pointer? (2) 

    x = reinterpret_cast<X*>(X::get() - X::get()); 
    (*x).f(); // the null pointer? (3) 

    (*(X*)0).f(); // I think that this the only null pointer here (4) 
} 

Il mio pensiero è che dereferenziazione del puntatore nullo avviene solo in quest'ultimo caso. Ho ragione? C'è differenza tra i point null di compilazione e il runtime secondo lo standard C++?

+0

Questo non è un compito a casa. Lo standard C++ non dice molto sul dereferenziamento dei puntatori nulli. Voglio solo sapere. –

+0

La prima parte della mia risposta parla del dereferencing dei puntatori nulli: http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in- undefined-behav (adoro questa domanda) – GManNickG

risposta

12

Solo il primo e l'ultimo sono puntatori nulli. Gli altri sono i risultati di reinterpret_cast e quindi operano sui valori di puntatore definiti dall'implementazione. Il fatto che il comportamento non sia definito per loro dipende dalla presenza o meno di un oggetto nell'indirizzo a cui sei stato assegnato.

+0

Qual è la differenza tra il dereferenziamento del puntatore nullo e un puntatore non valido? –

+0

@Johannes: sono dei puntatori nulli, ma causeranno un core dump? Inizialmente l'ho pensato, ma dopo un po 'di riflessione non ne sono così sicuro. Vedi la mia risposta sopra. –

+2

@ Scott Smith: la sua implementazione è definita. In particolare su piattaforme che non hanno alcun concetto di "core", ovvero qualcosa al di fuori di UNIX. –

12

Un'espressione costante intera che restituisce 0 è valida come puntatore nullo, quindi anche il primo caso dereferenzia un puntatore nullo.

Un puntatore che è impostato su 0 tramite un calcolo aritmetico non è necessariamente un puntatore nullo. Nella maggior parte delle implementazioni si comporta allo stesso modo di un puntatore nullo, ma questo non è garantito dallo standard.

+1

"La conversione di un'espressione di una costante integrale (5.19) con valore zero produce sempre un puntatore nullo (4.10), ma la conversione di altre espressioni che hanno valore zero non deve produrre un puntatore nullo" (5.2.10/5 nota 64). –

+1

@James Ahh! Quindi 0! = NULL per valori molto grandi di 0! – Earlz

+1

@Earlz: Ma 0! è 1! – GManNickG

0
X* x = 0; 
(*x).f(); // the null pointer? (1) 

penso che questo si qualifica come dereferenziare, anche se f() usa mai effettivamente il puntatore this, e non ci sono metodi virtuali in X. Il mio riflesso è stato dire che questo è un incidente, ma ora che ci penso, non ne sono così sicuro.

x = X::get(); 
(*x).f(); // the null pointer? (2) 

Probabilmente un puntatore non valido. non sono sicuro se si bloccherà (vedi sopra per il ragionamento).

x = reinterpret_cast<X*>(X::get() - X::get()); 
(*x).f(); // the null pointer? (3) 

Compilare l'espressione X::get() - X::get()? Non pensavo che fosse legale sottrarre un puntatore da un altro puntatore del genere.

EDIT: D'oh! Certo che è legale. Cosa stavo pensando? Chiaramente, sono un marrone.

+0

In riguarda la chiamata a una funzione non statica su un'istanza null: porta a un comportamento non definito. Quindi tutte le scommesse sono andate, chiaramente. Detto questo, in pratica fino a quando non è necessario il puntatore "this" (nessuna funzione virtuale, nessun membro, ecc.), Allora non si bloccherà, poiché non viene mai usato. – GManNickG

+0

I puntatori di sottrazione sono molto comuni e restituiranno la differenza tra i due puntatori. Tuttavia, poiché questi non sono nella stessa matrice, hai ragione - risultato indefinito. (ma probabilmente compila) – pm100

+0

@Scott Smith, l'ho appena compilato in GNU C++ ed eseguito senza errori. Perché pensi che i puntatori di sottrazione siano illegali? Il mio primo pensiero è che il codice nella domanda OP si bloccherà in (2). –

7

C++ standard (2003) 4.10

4.10 Pointer conversioni

1 Un puntatore costante nullo è un integrante costante espressione (5.19) rvalue di tipo intero che restituisce a zero. Una costante puntatore nullo può essere convertita in in un tipo di puntatore; il risultato è il valore del puntatore nullo di di quel tipo ed è distinguibile da ogni altro valore del puntatore all'oggetto o puntatore al tipo di funzione. Due valori di puntatore nulli dello stesso tipo devono essere uguali a . La conversione di un puntatore nullo costante su un puntatore al tipo con certificazione cv è una singola conversione e non la sequenza di una conversione puntatore seguita da una conversione di qualificazione (4.4).

5.2.10 reinterpretare getto

Nota 64) Conversione di un integrale costante espressione (5.19) con valore zero cede sempre un puntatore nullo (4.10), ma convertendo altre espressioni che capita di avere valore zero necessità non fornire un puntatore nullo.

1) X* x = 0; (*x).f(); Sì. 0 è un'espressione costante integrata e viene convertita nella costante del puntatore nullo. Quindi la costante del puntatore nullo può essere convertita nel valore del puntatore nullo.

2) x = X::get(); no, vedi nota 64 a 5.2.10

3) x = reinterpret_cast<X*>(X::get() - X::get()); no, vedi nota 64 a 5.2.10

4) ((X) 0) .f() ; Sì. 0 (espressione costante integrata) -> costante del puntatore nullo -> valore del puntatore nullo.

+0

Per la nota in 5.2.10, notare anche il rapporto sui difetti in http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#463 –

Problemi correlati