Не могу через указатель прочитать поле структуры
Есть у меня структура вида:
typedef union{
uint16_t word[32];
struct{
uint8_t Ho[32];
uint8_t Lo[32];
};
} _DIO_MIN;
typedef union{
uint16_t word[128];
struct{
uint8_t Ho[128];
uint8_t Lo[128];
};
} _DIO_MID;
typedef union{
uint16_t word[4096];
struct{
uint8_t Ho[4096];
uint8_t Lo[4096];
};
} _DIO_MAX;
typedef struct DIO{
unionDio DIO00;
_DIO_MIN DIO_MIN[63];
_DIO_MID DIO_MID[32];
_DIO_MAX DIO_MAX[4];
float GLOB[8192];
uint16_t ASUIO[32768];
uint8_t LOCALL[32768];
float STATDATA[32768];
char ERRORS[80];
int READYINPUT;
char DISP1[2][30][95];
char DISP2[2][30][95];
char DISP3[2][30][95];
char DISP4[2][30][95];
} _SysMem;
extern _SysMem SYSMEM;
Хочу по байтно обращаться через указатель к полям структуры для этого делаю:
uint8_t *addrSYSMEM = NULL;
addrSYSMEM = (uint8_t*)&SYSMEM;
SYSMEM.GLOB[0] = 16;
float a = *(addrSYSMEM + 45056);
Но в 'a' равно нулю. Не могу понять где не прав.
Ответы (3 шт):
В Вашем случаи использование статичного смешение будет плохо переносимым способом. Попробуйте проверить корректность Вашего смешения.
uint8_t *addrSYSMEM = (uint8_t*)&SYSMEM;
SYSMEM.GLOB[0] = 16.0;
int off = (int)&SYSMEM.GLOB - (int)&SYSMEM;
float a = *(float*)(addrSYSMEM + off);
Сначала нужно не забывать поменять тип указателя. А так-же в структурах сначала нужно узнать место элемента. Оно всегда упорядочено компилятором и тот добавляет пустые места (выравнивает).
Узнать смещение поля :
# include <stddef.h>
size_t const of_GLOB = offsetof ( _SysMem , GLOB ) ;
и тогда первый float можно получить :
float a = * ( float * ) (addrSYSMEM + of_GLOB);
И это ещё не всё. Побайтовый доступ конфликтует с оптимизацией компилятора. Он может удалить все "ненужные" присваивания и не считывать свежие значения, так-как думает, что ничего не изменилось. По-этому всегда делайте переменную volatile.
extern volatile _SysMem SYSMEM;
volatile _SysMem SYSMEM;
Все дело в том что возможно на вашей машине (как и на моей), порядок байт в машинном слове расположен как Little Endian.
int main(void) {
float a = 16.f;
unsigned char *b = (unsigned char *) &a;
for (size_t i = 0; i < sizeof(float); i++) {
printf("%d,", b[i]);
}
printf("\b\0\n"); /* удалить лишнюю запятую, и добавить перенос строки */
}
0, 0, 128, 65
Как вы видите, первый байт, равен нулю, отсюда у вас и берется тот самый нуль, т.к. вы приводите тип uint8_t к float aka ((float)((int8_t)0)) ~~ .0f, сам же float это совокупность 4х байт.
Но если же следовать примеру из комментариев который я оставил, то там ясно видно, что при приведении типа к оригинальному типу, его размерность будет правильно понята компилятором, и он будет копировать не 1й байт из указателя на int8_t, а sizeof(float) == 4.
Подробнее читайте на просторах.