Как установить значения массива в одну переменную - PullRequest
0 голосов
/ 16 июня 2019

Я читаю значения с SD-карты в ARM micro:

Res = f_read(&fil, (void*)buf, 6, &NumBytesRead);

, где fil - указатель, buf - буфер, в котором хранятся данные.

И в этом проблема: это массив, но я бы хотел, чтобы содержимое этого массива было в одной переменной.

Для примера: 6 байтов, прочитанных из файла:

buf[0] = 0x1B
buf[1] = 0x26
buf[2] = 0xB3
buf[3] = 0x54
buf[4] = 0xA1
buf[5] = 0xCF

И я бы хотел, чтобы: uint64_t data было равно 0x1B26B354A1CF. То есть все элементы массива «объединяются» в одно 64-разрядное целое число.

Ответы [ 3 ]

6 голосов
/ 16 июня 2019

Без ввода типа вы можете сделать, как показано ниже.

uint64_t data = 0;
for (int i=0; i<6; i++)
{
  data <<= 8;
  data |= (uint64_t) buf[i];
}
3 голосов
/ 16 июня 2019

Используйте союз, но помните о endianes.

 union 
 {
      uint8_t u8[8];
      uint64_t u64;
  }u64;

typedef union { uint8_t u8 [8]; uint64_t u64; } U64;

typedef enum
{
    LITTLE_E,
    BIG_E,
}ENDIANESS;

ENDIANESS checkEndianess(void)
{
    ENDIANESS result = BIG_E;
    u64 d64 = {.u64 = 0xff};
    if(d64.u8[0]) result = LITTLE_E;

    return result;
}

uint64_t arrayToU64(uint8_t *array, ENDIANESS e) // for the array BE
{
    u64 d64;
    if(e == LITTLE_E)
    {
        memmove(&d64, array, sizeof(d64.u64));
    }
    else
    {
        for(int index = sizeof(d64.u64) - 1; index >= 0; index--)
        {
            d64.u8[sizeof(d64.u64) - index - 1] = array[index];
        }
    }
    return d64.u64;
}

int main()
{
    uint8_t BIG_E_Array[] = {0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};
    ENDIANESS e;

    printf("This system endianess: %s\n", (e = checkEndianess()) == BIG_E ? "BIG":"LITTLE");

    printf("Punned uint64_t for our system 0x%lx\n", arrayToU64(BIG_E_Array, e));
    printf("Punned uint64_t for the opposite endianess system 0x%lx\n", arrayToU64(BIG_E_Array, e == BIG_E ? LITTLE_E : BIG_E));

    return 0;
}
0 голосов
/ 16 июня 2019

К вещам позаботиться здесь:

  1. чтобы байты были упорядочены правильно
  2. читать шесть байтов в одно 64-битное целое число

Проблема 1 может быть решена путем сохранения байта, поступающего в порядке сетевых байтов (Big Endian), в 64-битное целое число в порядке байтов хоста, например, с помощью двух полей ниже:

    /* below defines of htonll() and ntohll() are taken from this answer:
       https://stackoverflow.com/a/28592202/694576
     */
    #if __BIG_ENDIAN__
    # define htonll(x) (x)
    # define ntohll(x) (x)
    #else
    # define htonll(x) ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
    # define ntohll(x) ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
    #endif

Проблема 2 может быть решена несколькими способами:

  1. Расширение вашего подхода

    #define BUFFER_SIZE (6)
    
    ...
    
      assert(BUFFER_SIZE <= sizeof (uint64_t)); 
    
      uint8_t buffer[BUFFER_SIZE];
      FILE * pf = ...; /* open file here */
      /* test if file has been opened successfully here */
    
      ... result = f_read(pf, buffer, BUFFER_SIZE, ...);
      /* test result for success */
    
      uint64_t number = 0;
      memset(&number, buffer, BUFFER_SIZE)
      number = ntohll(number);
    
  2. Используйте " Type Punning ", используя объединение

    union buffer_wrapper
    {
      uint8_t u8[sizeof (uint64_t)];
      uint64_t u64;
    }
    

    вместо

      uint8_t buffer[BUFFER_SIZE];
    

    использование

      union buffer_wrapper buffer;
    

    и вместо

      memcpy(&number, buffer, BUFFER_SIZE)
      number = ntohll(number)
    

    использование

      number = ntohll(buffer.u64)
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...