2013-03-07 29 views
7

Dato che sono relativamente nuovo a C, devo utilizzare per uno dei miei progetti quanto segue: Devo dichiarare alcune variabili globali che devono essere memorizzate ogni volta che il programma viene eseguito con lo stesso indirizzo di memoria. Ho fatto un po 'di lettura e ho scoperto che è dichiarare "statico" che verrà memorizzato nella stessa posizione di memoria.Come memorizzare una variabile in una posizione di memoria specifica?

Ma la mia domanda è: posso indicare il programma in cui memorizzare quella variabile o meno. Ad esempio: int a da memorizzare su 0xff520000. Questa cosa può essere fatta o no? ho cercato qui ma non ho trovato alcun esempio pertinente. Se il loro è un vecchio post su questo, si prega di essere così gentile da condividere il link.

Grazie a tutti in anticipo. Laurentiu

Update: Sto usando un 32uC

+1

E 'comune sui sistemi embedded per avere registri hardware a indirizzi specifici. Tuttavia, su un normale PC non è possibile prevedere dove finiranno le variabili e non è possibile posizionare le variabili su posizioni di memoria specifiche in quanto la mappa di memoria di un programma non è fissa. È per un sistema embedded o per un normale PC? –

+1

Perché l'indirizzo è importante? È comunque ** memoria virtuale **. – UmNyobe

+0

Ciao, devo fare quanto segue. Esegui una sorta di piattaforma di prova per un UC a 32 bit, ma dopo aver lampeggiato tramite OCD, la piattaforma dovrebbe avere (eseguito) sulla comunicazione UART. E diciamo che ho un contatore che conta quante volte il programma è stato eseguito, o un contatore che memorizza quante volte il programma viene eseguito senza errori, quindi il mio professore cosa dare come input tramite Hyper Terminal l'indirizzo in cui si trova quel contatore variabile, per ottenere il suo valore Questo è quello che mi serve ... qualsiasi idea: – Laurentiu

risposta

10

Nel tuo IDE ci sarà una mappa di memoria disponibile attraverso qualche file linker. Conterrà tutti gli indirizzi nel programma. Leggi il manuale della MCU per vedere a quali indirizzi c'è una memoria valida per il tuo scopo, quindi riservane parte della memoria per la tua variabile. Devi leggere la documentazione della tua piattaforma di sviluppo specifica.

Successivamente, si noti che non ha molto senso mappare le variabili su indirizzi specifici a meno che non si tratti di registri hardware o variabili non volatili residenti in flash o EEPROM.

Se il contenuto di una tale posizione di memoria cambieranno durante l'esecuzione, in quanto si tratta di un registro, o perché il programma contiene un algoritmo di programmazione bootloader/NVM cambiando celle di memoria NVM, quindi le variabili deve essere dichiarata come volatile. Altrimenti il ​​compilatore interromperà completamente il codice dopo l'ottimizzazione.

Il particolare compilatore ha probabilmente un modo non standard per allocare le variabili su indirizzi specifici, ad esempio #pragma o talvolta l'operatore strano, non standard @. L'unico modo sensato è possibile assegnare una variabile in una posizione fissa nella norma C, è questo:

#define MY_REGISTER (*(volatile uint8_t*)0x12345678u) 

dove 0x12345678 è l'indirizzo in cui si trova 1 byte di questo. Una volta che avete una dichiarazione macro come questo, è possibile utilizzarlo come se fosse una variabile:

void func (void) 
{ 
    MY_REGISTER = 1; // write 
    int var = MY_REGISTER; // read 
} 

Il più delle volte si desidera questo tipo di variabili di risiedere nel namespace globale, da cui il macro. Ma se per qualche motivo si desidera che il campo di applicazione della variabile di ridurre, quindi saltare la macro e accedere manualmente l'indirizzo all'interno del codice:

void func (void) 
{ 
    *(volatile uint8_t*)0x12345678u = 1; // write 
    int var = *(volatile uint8_t*)0x12345678u; // read 
} 
+0

Grazie.Questo è quello che volevo. Ho seguito il tuo consiglio e ho trovato il seguente: MEMORIA IROM \t: ORIGINE = 0x00000000, \t LUNGHEZZA = 3072K Iram \t: ORIGINE = 0xFEDC0000, \t LUNGHEZZA = 256k Buram \t: ORIGINE = 0xFF760000, \t LUNGHEZZA = 16k
suppongo devo selezionare un intervallo dalla RAM da quello che ho bisogno giusto? – Laurentiu

+1

A proposito: io perché hai usato l'indirizzo 0x12345678u? cosa rappresenta la fine della fine? – Laurentiu

+2

@Laurentiu Un suffisso 'u' (o' U') significa che il valore letterale intero è di tipo 'unsigned'. È lì per garantire che venga usato il tipo rientrato, l'ho scritto principalmente per abitudine. Un intero letterale in C source è di tipo (signed) 'int' di default, ma poiché un indirizzo non può mai essere negativo, non ha senso usare una variabile firmata per memorizzarlo. In generale, non si desidera utilizzare il tipo predefinito 'int' nei sistemi incorporati. In alcuni casi, quando si esegue una semplice aritmetica, è possibile utilizzare i tipi 'sintN_t', dove N = 8, 16 ecc. Ma la maggior parte delle volte, si usano solo variabili non firmate. – Lundin

1

No, non si può dire in modo esplicito dove memorizzare una variabile nella memoria. Principalmente perché su sistemi moderni hai molte cose fatte dal sistema riguardo alla memoria, che è fuori dal tuo controllo. Address Layout La randomizzazione è una cosa che viene in mente che renderebbe tutto questo molto difficile.

0

Non al livello C. Se lavori con il linguaggio assembly, puoi controllare direttamente il layout della memoria. Ma il compilatore C fa questo per te. Non puoi davvero scherzare.

Anche con il montaggio, questo controlla solo il layout relativo. La memoria virtuale può collocarla in qualsiasi (in) comoda posizione fisica.

8

È possibile fare questo genere di cose con script di linker, che è abbastanza comune nella programmazione incorporata.

Su un sistema Linux non si potrebbe mai ottenere lo stesso indirizzo virtuale a causa della randomizzazione dello spazio degli indirizzi (una funzione di sicurezza per evitare exploit che farebbero affidamento sulla conoscenza della posizione esatta di una variabile come si descrive).

Se si tratta solo di un puntatore ripetibile, è possibile mappare un indirizzo specifico con mmap, ma ciò non è garantito.

+0

Vero. Poiché penso che usare mmap, mappare lo spazio degli indirizzi in file potrebbe risolvere il problema. La sua sola cura dovrà essere presa in modo che mmap (CONST_ADDR, ....., fd, CONST_FILE_OFFSET); non fallirà mai (o mapperà a diff-addr di COSNT_ADDR). Quindi CONST_ADDR diventa l'indirizzo della variabile globale e le modifiche apportate a questo contatore globale si rifletteranno nel file, che potrebbe essere utilizzato ulteriormente nel prossimo programma. –

0

Si può fare questo con alcune estensioni del compilatore, ma probabilmente non è quello che si vuole fare. Il sistema operativo gestisce la tua memoria e metterà le cose dove vuole. Come fai a sapere che l'indirizzo di memoria che vuoi sarà mappato nel tuo programma? Ignora tutto in questo paragrafo se sei su una piattaforma embedded, quindi dovresti leggere il manuale per quella piattaforma/compilatore o almeno menzionarlo qui in modo che le persone possano dare una risposta più specifica.

Inoltre, le variabili statiche non hanno necessariamente lo stesso indirizzo durante l'esecuzione del programma. Molti sistemi operativi utilizzano gli eseguibili indipendenti dalla posizione e randomizzano lo spazio degli indirizzi su ogni esecuzione.

0

è possibile dichiarare un puntatore a un indirizzo di memoria specifico e utilizzare i contenuti di quel puntatore come una variabile suppongo:

int* myIntPointer = 0xff520000; 
+0

typecast it. – anishsane

1

Come è stato menzionato in altre risposte - non è possibile. Ma puoi avere una soluzione alternativa. Se è ok per le variabili globali per essere inizializzati nel main(), si può fare qualcosa di questo genere:

int addr = 0xff520000; 

int main() 
{ 
    *((int*)addr) = 42; 
    ... 
    return 0; 
} 

Si noti, tuttavia, che questo è molto dipende dal sistema e se in esecuzione in ambiente protetto, ti molto probabilmente si verifica un arresto anomalo del runtime.Se ti trovi in ​​un ambiente embedded/non protetto, questo può funzionare.

+0

Questo funziona. Per favore, puoi dirmi come posso trovare una posizione in cui memorizzare effettivamente la mia variabile? Perché suppongo di non poter usare alcune aree di memoria ramdom dell'uC? – Laurentiu

+0

@Laurentiu Nel tuo IDE ci sarà una mappa di memoria disponibile attraverso qualche file linker. Conterrà tutti gli indirizzi nel programma. Leggi il manuale della MCU per vedere a quali indirizzi c'è una memoria valida per il tuo scopo, quindi riservane parte della memoria per la tua variabile. Devi leggere la documentazione della tua piattaforma di sviluppo specifica. – Lundin

Problemi correlati