Pointer (programmazione per computer)
AdaEdit
Ada è un linguaggio fortemente tipizzato in cui tutti i puntatori sono digitati e sono consentite solo conversioni di tipo sicure. Tutti i puntatori vengono inizializzati per impostazione predefinita su null
e qualsiasi tentativo di accedere ai dati tramite un puntatore null
provoca il sollevamento di un’eccezione. I puntatori in Ada sono chiamati tipi di accesso. Ada 83 non consentiva l’aritmetica sui tipi di accesso (sebbene molti fornitori di compilatori lo fornissero come funzionalità non standard), ma Ada 95 supporta l’aritmetica “sicura” sui tipi di accesso tramite il pacchetto System.Storage_Elements
.
BASICEdit
Diverse vecchie versioni di BASIC per la piattaforma Windows avevano il supporto per STRPTR () per restituire l’indirizzo di una stringa e per VARPTR () per restituire l’indirizzo di una variabile. Visual Basic 5 supportava anche OBJPTR () per restituire l’indirizzo di un’interfaccia oggetto e per un operatore ADDRESSOF per restituire l’indirizzo di una funzione. I tipi di tutti questi sono numeri interi, ma i loro valori sono equivalenti a quelli contenuti nei tipi di puntatore.
I dialetti più recenti del BASIC, come FreeBASIC o BlitzMax, hanno implementazioni di puntatore esaustive, tuttavia. In FreeBASIC, l’aritmetica su ANY
equivalenti a C “s void*
) vengono trattati come se il puntatore ANY
fosse una larghezza di byte. I puntatori di ANY
non possono essere dereferenziati, come in C. Inoltre, il casting tra puntatori di ANY
e di qualsiasi altro tipo “s non genererà alcun avviso.
dim as integer f = 257dim as any ptr g = @fdim as integer ptr i = gassert(*i = 257)assert( (g + 4) = (@f + 1) )
Modifica C e C ++
In C e C ++ i puntatori sono variabili che memorizzano indirizzi e può essere nullo. Ogni puntatore ha un tipo a cui punta, ma è possibile eseguire liberamente il cast tra i tipi di puntatore (ma non tra un puntatore a funzione e un puntatore a oggetto). Un tipo di puntatore speciale chiamato “puntatore vuoto” consente di puntare a qualsiasi (non -funzione) oggetto, ma è limitato dal fatto che non può essere dereferenziato direttamente (deve essere lanciato). L’indirizzo stesso può spesso essere manipolato direttamente eseguendo il cast di un puntatore ae da un tipo integrale di dimensioni sufficienti, sebbene i risultati siano definiti dall’implementazione e possano effettivamente causare un comportamento indefinito; mentre i precedenti standard C non avevano un tipo integrale che fosse garantito essere abbastanza grande, C99 specifica il uintptr_t
nome typedef definito in <stdint.h>
, ma non è necessario che un’implementazione lo fornisca.
C ++ supporta completamente i puntatori C e il typecasting C. Supporta anche un nuovo gruppo di operatori di typecasting per aiutare a catturare alcuni cast pericolosi non intenzionali in fase di compilazione. A partire da C ++ 11, la libreria standard C ++ fornisce anche puntatori intelligenti (unique_ptr
, shared_ptr
e weak_ptr
) che può essere utilizzato in alcune situazioni come alternativa più sicura ai puntatori C primitivi. C ++ supporta anche un’altra forma di riferimento, molto diversa da un puntatore, chiamata semplicemente riferimento o tipo di riferimento.
Aritmetica del puntatore, ovvero la capacità di modificare l’indirizzo di destinazione di un puntatore con operazioni aritmetiche (come così come i confronti di grandezza), è limitato dallo standard del linguaggio a rimanere entro i limiti di un singolo oggetto array (o subito dopo di esso), e altrimenti invocherà un comportamento indefinito. L’aggiunta o la sottrazione da un puntatore lo sposta di un multiplo della dimensione del suo tipo di dati. Ad esempio, aggiungendo 1 a un puntatore a valori interi a 4 byte si incrementerà di 4 l’indirizzo a byte puntato del puntatore. Ciò ha l’effetto di incrementare il puntatore in modo che punti all’elemento successivo in un contiguo matrice di numeri interi, che spesso è il risultato desiderato. L’aritmetica dei puntatori non può essere eseguita sui puntatori void
perché il tipo void non ha dimensione e quindi l’indirizzo puntato non può essere aggiunto, sebbene gcc e altri compilatori eseguiranno l’aritmetica dei byte su void*
come un’estensione non standard, trattandola come se fosse char *
.
L’aritmetica dei puntatori fornisce al programmatore un un unico modo di trattare i diversi tipi: sommando e sottraendo il numero di elementi richiesti invece dell’effettivo offset in byte. (L’aritmetica del puntatore con puntatori char *
utilizza offset di byte, perché sizeof(char)
è 1 per definizione.) In particolare, la definizione C dichiara esplicitamente che il la sintassi a
, che è il n
-esimo elemento dell’array a
, è equivalente a *(a + n)
, che è il contenuto dell’elemento indicato da a + n
. Ciò implica che n
è equivalente a a
e si può scrivere, ad esempio, a
oppure 3
altrettanto bene per accedere al quarto elemento di un array a
.
Sebbene potente, l’aritmetica dei puntatori può essere una fonte di bug del computer. Tende a confondere i programmatori alle prime armi, costringendoli a entrare in contesti diversi: un’espressione può essere una normale espressione aritmetica o una puntatrice aritmetica, ea volte è facile scambiarle l’una per l’altra. In risposta a ciò, molti linguaggi per computer moderni di alto livello (ad esempio Java) non consentono l’accesso diretto alla memoria utilizzando indirizzi. Inoltre, il dialetto C sicuro Cyclone risolve molti dei problemi con i puntatori. Vedere il linguaggio di programmazione C per ulteriori discussioni.
Il puntatore void
, o void*
, è supportato in ANSI C e C ++ come tipo di puntatore generico. Un puntatore a void
può memorizzare l’indirizzo di qualsiasi oggetto (non funzione) e, in C, viene convertito implicitamente in qualsiasi altro tipo di puntatore a oggetto durante l’assegnazione, ma deve essere cast esplicitamente se dereferenziato.K & RC ha utilizzato char*
per lo scopo del “puntatore indipendente dal tipo” (prima di ANSI C).
C ++ non consente la conversione implicita di void*
ad altri tipi di puntatori, anche negli assegnamenti. Questa è stata una decisione progettuale per evitare cast imprudenti e anche involontari, sebbene la maggior parte dei compilatori emetta solo avvisi , non errori, quando si incontrano altri cast.
In C ++, non c’è void&
(riferimento a void) per completare void*
(puntatore a void), perché i riferimenti si comportano come alias delle variabili a cui puntano e non può mai esserci una variabile il cui tipo è void
.
Panoramica della sintassi della dichiarazione del puntatore Modifica
Queste dichiarazioni del puntatore c sulla maggior parte delle varianti delle dichiarazioni di puntatore. Ovviamente è possibile avere puntatori tripli, ma i principi fondamentali alla base di un puntatore triplo esistono già in un puntatore doppio.
Le () e hanno una priorità più alta di *.
Modifica C #
Nel linguaggio di programmazione C #, i puntatori sono supportati solo a determinate condizioni: qualsiasi blocco di codice che include puntatori deve essere contrassegnato con la parola chiave unsafe
. Tali blocchi di solito richiedono permessi di sicurezza più elevati per poter essere eseguiti. La sintassi è essenzialmente la stessa di C ++ e l’indirizzo puntato può essere memoria gestita o non gestita. Tuttavia, i puntatori alla memoria gestita (qualsiasi puntatore a un oggetto gestito) devono essere dichiarati utilizzando la parola chiave fixed
, che impedisce al garbage collector di spostare l’oggetto puntato come parte della gestione della memoria mentre il il puntatore è nello scope, mantenendo così valido l’indirizzo del puntatore.
Un’eccezione a ciò è data dall’utilizzo della struttura IntPtr
, che è un equivalente gestito in sicurezza di int*
e non richiede codice non sicuro. Questo tipo viene spesso restituito quando si utilizzano metodi dal System.Runtime.InteropServices
, ad esempio:
Il framework .NET include molte classi e metodi nel System
e System.Runtime.InteropServices
spazi dei nomi (come la classe Marshal
) che convertono i tipi .NET (ad esempio, System.String
) da e verso molti tipi e puntatori non gestiti (ad esempio, LPWSTR
o void*
) per consentire comunicazione con codice non gestito. La maggior parte di questi metodi ha gli stessi requisiti di autorizzazione di sicurezza del codice non gestito, poiché possono influire su posizioni arbitrarie della memoria.
COBOLEdit
Il linguaggio di programmazione COBOL supporta i puntatori a variabili. Gli oggetti dati primitivi o di gruppo (record) dichiarati all’interno di LINKAGE SECTION
di un programma sono intrinsecamente basati su puntatori, dove l’unica memoria allocata all’interno del programma è lo spazio per l’indirizzo dell’elemento dati ( tipicamente una singola parola di memoria). Nel codice sorgente del programma, questi elementi di dati vengono utilizzati come qualsiasi altra variabile WORKING-STORAGE
, ma ai loro contenuti si accede indirettamente in modo implicito tramite i puntatori LINKAGE
.
Lo spazio di memoria per ogni oggetto dati a cui si fa riferimento viene solitamente allocato dinamicamente utilizzando istruzioni CALL
esterne o tramite costrutti di linguaggio estesi incorporati come EXEC CICS
o EXEC SQL
.
Le versioni estese di COBOL forniscono anche variabili puntatore dichiarate con USAGE
Clausole IS
POINTER
. I valori di tali variabili puntatore vengono stabiliti e modificati utilizzando le istruzioni SET
e SET
ADDRESS
.
Alcune versioni estese di COBOL forniscono anche PROCEDURE-POINTER
variabili, che sono in grado di memorizzare gli indirizzi del codice eseguibile.
PL / IEdit
Il linguaggio PL / I fornisce pieno supporto per i puntatori a tutti i tipi di dati (inclusi i puntatori a strutture), ricorsione, multitasking, gestione delle stringhe e numerose funzioni integrate.PL / I è stato un bel balzo in avanti rispetto ai linguaggi di programmazione del suo tempo. I puntatori PL / I non sono tipizzati e pertanto non è richiesto alcun casting per la dereferenziazione o l’assegnazione del puntatore. La sintassi della dichiarazione per un puntatore è DECLARE xxx POINTER;
, che dichiara un puntatore denominato “xxx”. I puntatori vengono utilizzati con le variabili BASED
. Una variabile basata può essere dichiarata con un localizzatore predefinito (DECLARE xxx BASED(ppp);
o senza (DECLARE xxx BASED;
), dove xxx è una variabile basata, che può essere una variabile di elemento, una struttura o un array e ppp è il puntatore predefinito). Una tale variabile può essere un indirizzo senza un riferimento esplicito a un puntatore (xxx=1;
, o può essere indirizzata con un riferimento esplicito al localizzatore predefinito (ppp) o a qualsiasi altro puntatore (qqq->xxx=1;
).
L’aritmetica dei puntatori non fa parte dello standard PL / I, ma molti compilatori consentono espressioni nella forma ptr = ptr±expression
. IBM PL / I ha anche la funzione incorporata PTRADD
per eseguire l’aritmetica. L’aritmetica del puntatore viene sempre eseguita in byte.
I compilatori IBM Enterprise PL / I hanno un nuova forma di puntatore digitato chiamato HANDLE
.
DEdit
Il linguaggio di programmazione D è un derivato di C e C ++ che supporta completamente C puntatori e typecast in C.
EiffelEdit
Il linguaggio orientato agli oggetti Eiffel utilizza la semantica di valori e di riferimento senza aritmetica dei puntatori. Tuttavia, vengono fornite classi di puntatori. Offrono aritmetica dei puntatori, typecast, esplicite gestione della memoria, int che si affaccia con software non Eiffel e altre funzionalità.
FortranEdit
Fortran-90 ha introdotto una capacità di puntatore fortemente tipizzato. I puntatori Fortran contengono più di un semplice indirizzo di memoria. Incapsulano anche i limiti inferiore e superiore delle dimensioni dell’array, dei passi (ad esempio, per supportare sezioni arbitrarie dell’array) e di altri metadati. Un operatore di associazione, =>
viene utilizzato per associare un POINTER
a una variabile che ha un TARGET
attributo. L’istruzione ALLOCATE
Fortran-90 può essere utilizzata anche per associare un puntatore a un blocco di memoria. Ad esempio, il codice seguente potrebbe essere utilizzato per definire e creare una struttura di elenchi collegati:
Fortran-2003 aggiunge il supporto per i puntatori a procedure. Inoltre, come parte della funzionalità di interoperabilità C, Fortran-2003 supporta funzioni intrinseche per convertire i puntatori in stile C in puntatori Fortran e viceversa.
GoEdit
Go ha puntatori. La sua sintassi di dichiarazione è equivalente a quella di C, ma scritta al contrario, terminando con il tipo. A differenza di C, Go ha la garbage collection e non consente l’aritmetica dei puntatori. I tipi di riferimento, come in C ++, non esistono. Alcuni tipi incorporati, come mappe e canali, sono in box (cioè internamente sono puntatori a strutture mutabili) e vengono inizializzati utilizzando la funzione make
. In un approccio alla sintassi unificata tra puntatori e non puntatori, l’operatore freccia (->
) è stato abbandonato: l’operatore punto su un puntatore si riferisce al campo o al metodo dell’oggetto dereferenziato . Questo, tuttavia, funziona solo con 1 livello di riferimento indiretto.
JavaEdit
A differenza di C, C ++ o Pascal, non esiste una rappresentazione esplicita dei puntatori in Java. Invece, strutture di dati più complesse come oggetti e array vengono implementate utilizzando riferimenti. Il linguaggio non fornisce alcun operatore esplicito di manipolazione del puntatore. È comunque possibile che il codice tenti di dereferenziare un riferimento nullo (puntatore nullo), il che si traduce in un’eccezione in fase di esecuzione. Lo spazio occupato da oggetti di memoria non referenziati viene recuperato automaticamente dalla garbage collection in fase di esecuzione.
Modula-2Edit
I puntatori sono implementati molto come in Pascal, così come VAR
parametri nelle chiamate di procedura. Modula-2 è tipizzato ancora più fortemente di Pascal, con meno modi per sfuggire al sistema di tipi. Alcune delle varianti di Modula-2 (come Modula-3) includono la garbage collection.
OberonEdit
Proprio come con Modula-2, i puntatori sono disponibili. Ci sono ancora meno modi per eludere il sistema dei tipi e quindi Oberon e le sue varianti sono ancora più sicuri rispetto ai puntatori rispetto a Modula-2 o alle sue varianti. Come con Modula-3, la garbage collection fa parte delle specifiche del linguaggio.
PascalEdit
A differenza di molti linguaggi che dispongono di puntatori, lo standard ISO Pascal consente solo ai puntatori di fare riferimento a variabili create dinamicamente che sono anonimi e non consentono loro di fare riferimento a variabili statiche o locali standard. Non ha aritmetica dei puntatori. I puntatori devono anche avere un tipo associato e un puntatore a un tipo non è compatibile con un puntatore a un altro tipo (ad esempio un puntatore a un carattere non è compatibile con un puntatore a un numero intero).Questo aiuta ad eliminare i problemi di sicurezza del tipo inerenti ad altre implementazioni di puntatori, in particolare quelli usati per PL / I o C. Rimuove anche alcuni rischi causati da puntatori penzolanti, ma la capacità di lasciar andare dinamicamente lo spazio di riferimento usando dispose
procedura standard (che ha lo stesso effetto della funzione di libreria free
trovata in C) significa che il rischio di puntatori penzolanti non è stato completamente eliminato.
Tuttavia, in alcune implementazioni di compilatori Pascal (o derivati) commerciali e open source – come Free Pascal, Turbo Pascal o Object Pascal in Embarcadero Delphi – un puntatore può fare riferimento a variabili statiche o locali standard e può essere cast da un tipo di puntatore a un altro. Inoltre, l’aritmetica del puntatore è illimitata: l’aggiunta o la sottrazione da un puntatore lo sposta di quel numero di byte in entrambe le direzioni, ma utilizzando Inc
o Dec
procedure standard con esso sposta il puntatore della dimensione del tipo di dati a cui è dichiarato puntare. Viene fornito anche un puntatore non tipizzato con il nome Pointer
, compatibile con altri tipi di puntatore.