Visualizzazione dei risultati da 1 a 4 su 4
  1. #1

    [C] Puntamento a null casuale

    Buongiorno.
    Lo standard C dice che:
    - per variabili con static storage duration, ovvero le globali e le locali static, se non viene specificata un'inizializzazione esplicita vengono inizializzate a zero;
    - in tutti gli altri casi, nascono "non inizializzate", il che significa che è "undefined behavior" accedervi in lettura prima di averci scritto qualcosa.
    Domanda: "undefined behavior", incluso cacciarsi "casualmente" proprio dentro nullptr?
    Mi sembra strano, stranissimo, ... avrei negato la cosa... ed è il motivo della mia domanda.
    Ma se così non fosse, non mi spiego perchè accade quanto segue:
    int *p;
    cout<<*p<<endl;
    funziona, dando una risposta a casaccio (ok: il puntatore non inizializzato, contiene un intero qualsiasi, a caso)
    Ad esempio: -125990072

    Invece, inserendo inutili e inutilizzate variabili in testa, tanto per "sporcare" un po'lo stack, Xcode mi butta fuori:
    int a;
    int b;
    int *p;
    cout<<*p<<endl;

    Il compilatore (sto usando Xcode, su mac) dice che l'interruzione è sul primo thread, dando questo messaggio d'errore:
    Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)

    Xcode, a margine, indica il contenuto dentro le celle a, b come interi casuali (mi sembra normale), ma il suo problema è leggere il contenuto di p, perchè ora p punta a NULL.
    Secondo lui (con copia e incolla da Xcode)
    p = (int *) NULL

    Mi sembra così strano che, "casualmente", si cacci proprio lì dentro... che chiedo conferma!
    Grazie

    PS ho inserito qui la mia domanda. Corretto? C'è un link migliore? Ari-Grazie.
    Buona giornata.
    Claudia C.

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,241
    Non ho capito ... certamente un puntatore può casualmente essere null, chi lo vieta? Ma c'è un'altra questione che non hai considerato ... anche con un valore diverso da zero puoi avere due comportamenti diversi (crash o normale funzionamento), a seconda che il puntatore sia casualmente nell'area degli indirizzi allocato al processo o no.

    Per capire meglio, visualizza il valore del puntatore nel tuo codice.
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    int *p;
    cout<<*p<<endl;
    funziona, dando una risposta a casaccio (ok: il puntatore non inizializzato, contiene un intero qualsiasi, a caso)
    No attenzione: il puntatore concettualmente non contiene un intero qualsiasi, ma un indirizzo qualsiasi. Ti è andata bene che di fortuna ci fosse un indirizzo che puntava a memoria valida. Viceversa, poi, sempre di fortuna, ti sei beccata un NULL.

    Ora, la fortuna in realtà c'entra fino a un certo punto; NULL e puntatori validi sono entrambe possibilità abbastanza frequenti per variabili non inizializzate.

    Nel momento in cui vai a leggere roba non inizializzata dallo stack, all'atto pratico stai andando a pescare o valori di vecchie variabili che stavano in quel punto lì dello stack in una qualche chiamata precedente, o return address/frame pointers, oppure stai iniziando ad usare zone di stack finora non ancora impiegate (caso tipico se è un programma piccolo e questa è una delle prime funzioni con un po' di locali ad essere invocata).

    Nel primo caso, ci sono discrete probabilità che in qualche chiamata precedente qualcuno abbia avuto una variabile locale puntatore a qualcosa di valido e i return address e i frame pointer sono sempre puntatori validi; viceversa, le zone di stack non inizializzate sulla maggior parte dei sistemi operativi moderni di default sono pagine inizializzate a zero, e quindi lette come puntatori sono dei null pointer.

    Nota: tutto questo ovviamente non è contrattuale, ma è una spiegazione di comportamenti che di solito si incontrano; in particolare, abilita le ottimizzazioni e vedrai tante di queste cose cadere - variabili che prima stavano sullo stack potrebbero finire nei registri o sparire completamente (se non le usi, o se le usi solo come appoggio), l'inlining potrebbe togliere in blocco intere chiamate a funzione, e più in generale l'ottimizzatore è autorizzato ad assumere che l'undefined behavior non possa mai capitare, quindi compilando in maniera sorprendente codice che presenta UB.
    Amaro C++, il gusto pieno dell'undefined behavior.

  4. #4
    Grazie a entrambi.
    Chiarissimo!
    Buon tutto.
    Alla prossima

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2019 vBulletin Solutions, Inc. All rights reserved.