2015-11-03 12 views
5

Supponiamo di avere un puntatore uint8_t al terzo elemento di un array, {1, 2, 4, 5} quindi *p è 4. Come posso farlo puntare a 4 e 5 in modo che *p sia 45. È persino possibile? Attualmente sto convertendo in tipografia. Ecco cosa faccio, ad es. se i dati è la mia serie {1, 2, 4, 5} e voglio ottenere 4 e 5.Come puntare il puntatore a due o più celle consecutive

uint8_t dummyAddress = data[2]; 
dummyAddress = *((uint16_t*) dummyAddress); 
*p = *dummyAddress; 

mia comprensione è che p dovrebbe ora puntare a 4 e 5, ma io non sono. Invece ottengo un errore di seg quando eseguo la seconda linea. p è un uint64_t * const. Funziona per ottenere un byte, ma quando si applica la stessa logica a due byte non riesco a farlo bene.

+0

Fornire codice completo (dichiarazione array, tipi di variabili utilizzate, ...). –

+0

Dovresti compilare con un livello di avviso più alto e ascoltare gli avvisi del compilatore. –

+1

Nel tuo codice 'dummyAddress' non è un puntatore –

risposta

4

Si può fare questo:

uint8_t data[] = { 1, 2, 4, 5 }; 
uint8_t *p8 = &data[2]; 
uint16_t u16 = *(uint16_t*)p8; 

Poi (uint16_t*)p8 punterà a data[2] e data[3]. Ma non è possibile accedere facilmente a *(uint16_t*)p8. Innanzitutto perché p8 potrebbe non essere allineato al limite uint16_t. Alcuni processori causano un'eccezione in questo caso. In secondo luogo, anche se è possibile accedere a *(uint16_t*)p8, si potrebbero ottenere risultati diversi a seconda dell'ordine dei byte del processore (big endian/little endian). Potresti ricevere 0x0405 o potresti ricevere 0x0504.

Si prega di notare, inoltre, che nella vostra linea

dummyAddress = *((uint16_t*) dummyAddress); 

si sono prima reinterpretando dummyAddress come un puntatore a uint16_t e poi dereferenziazione, in modo da restituire un uint16_t e memorizzando questo dummyAddress. Questo chiaramente non è ciò che volevi fare. Se questo è veramente compilato, ti preghiamo di prendere in considerazione la compilazione con un livello di avviso più alto e dare un'occhiata ad ogni avvertimento del compilatore (e ignorarlo solo se lo capisci e sei certo che non si tratta di un errore di programmazione).

BTW, non sarà possibile ottenere un puntatore p dove *p==45 come richiesto nella domanda.

Inoltre, come MCH ha detto: What is the strict aliasing rule?

+0

per impostazione predefinita sembra che acquisisca i byte in little endian, quindi * p è 0x0504. ora se voglio invertire così * p legge 0x405 sono confuso su come farlo. Ho visto persone usare l'operatore << e spostare i bit 8 volte o moltiplicare * p per 256 un certo numero di volte? Qualsiasi spiegazione per favore – ponderingdev

+1

Sì, puoi farlo con lo spostamento come 'uint16_t a = ...; uint16_t b = (a >> 8) | (a << 8) '. Ancora meglio funziona direttamente sull'array di dati 'uint16_t b = ((uint16_t) data [2] << 8) | data [3] '(o scambio dati [2] e dati [3]). –

0

si dovrebbe scrivere:

uint_8_t *dummyAddress= &data[2]; 
uint_16_t *dummyAddress2= (uint16_t *) dummyAddress; 

uint_16_t p= *dummyAddress2; 

ma nota che a causa di "endianness" è possibile ottenere i due uint_8 s' nell'ordine sbagliato, vale a dire come {data[3], data[2} .

+2

ed è un comportamento non definito poiché viola la regola di aliasing. – mch

1

Se ho capito cosa stai facendo, allora sì, puoi accedere a entrambi i byte lanciando a uint16_t, ma ti imbatterai in problemi (o problemi di endianess) con come l'ordine i byte sono archiviati in memoria così come violare strict-aliasing. Questo probabilmente restituirà una risposta che non sospettavi. Ad esempio:

#include <stdio.h> 
#include <stdint.h> 

int main (void) { 

    uint8_t array[] = {1,2,3,4}; 
    uint8_t *p = array + 2; 

    printf ("\n the uint8_t answer : %hhd\n", *p); 
    printf (" the uint16_t answer : %hd\n\n", *(uint16_t *)p); 

    printf ("**note: the will cast result in bytes 4, 3" 
      " (or (4 << 8 | 3) = 1027)\n\n"); 

    return 0; 
} 

uscita

$ ./bin/cast_array 

the uint8_t answer : 3 
the uint16_t answer : 1027 

**note: the cast will result in bytes 4, 3 (or (4 << 8 | 3) = 1027) 

I byte sono memorizzati nella memoria nel mio sistema in little endian ordine. Quindi, quando lanci su uint16_t, si aspetta di trovare least significant, most significant byte.Quale nell'esempio sopra con 34 nella memoria, il cast interpreterà l'ordine effettivo come 43 risultante in un valore di 1027 anziché (3 << 8) | 4 = 772.

Come è noto, vi sarà violare le regole relative alla rigorosa aliasing dove tipo di potatura per colata a qualcosa di diverso da char risultati in un comportamento indefinito. I risultati di tutte queste azioni dipendono dall'hardware e dal compilatore e non dovrebbero essere utilizzati per scopi diversi dall'esercizio di apprendimento.

+0

'* (uint16_t *) p' richiama il comportamento non definito, poiché viola la regola di aliasing. – mch

+0

Sì. Tralascio una nota riguardante l'eliminazione dei tipi. –

Problemi correlati