Как разобрать строку в структуру? - PullRequest
0 голосов
/ 10 мая 2018

Я хочу знать, есть ли способ преобразовать строку типа "5ABBF13A000A01" в следующую структуру, используя метод struct и union:

struct xSensorData2{
    unsigned char flags;           
    unsigned int refresh_rate;
    unsigned int timestamp;
};

Данные должны быть:

flags = 0x01 (last byte);
refresh_rate = 0x000A (two bytes);
timestamp = 5ABBF13A (four bytes);

Я думаю о следующей структуре данных:

struct xData{
    union{
        struct{
            unsigned char flags:8;
            unsigned int refresh_rate:16;
            unsigned int timestamp:32;
        };
        char pcBytes[8];
    };
}__attribute__ ((packed));

Но я получил структуру из 12 байтов, я думаю, это потому, что битовые поля не работают для разных типов данных. Я должен просто преобразовать строку в массив hex, скопировать в pcBytes и иметь доступ к каждому полю.

Обновление: На платформе stm32 я использовал этот код:

bool bDecode_HexString(char *p)
{
uint64_t data = 0;                  /* exact width type for conversion 
*/
char *endptr = p;                   /* endptr for strtoul validation */
errno = 0;                                          /* reset errno */

data = strtoull (p, &endptr, 16);    /* convert input to uint64_t */

if (p == endptr && data == 0) {     /* validate digits converted */
    fprintf (stderr, "error: no digits converted.\n");
    return false;
}
if (errno) {    /* validate no error occurred during conversion */
    fprintf (stderr, "error: conversion failure.\n");
    return false;
}
//printf ("data: 0x%" PRIx64 "\n\n", data); /* output conerted string */

sensor.flags = data & 0xFF;                             /* set flags */
sensor.rate = (data >> CHAR_BIT) & 0xFFFF;              /* set rate */
sensor.tstamp = (data >> (3 * CHAR_BIT)) & 0xFFFFFFFF;  /* set timestamp */

    return true;

/* output sensor struct */
//    printf ("sensor.flags : 0x%02" PRIx8 "\nsensor.rate  : 0x%04" PRIx16
//            "\nsensor.tstamp: 0x%08" PRIx32 "\n", sensor.flags, sensor.rate,
//            sensor.tstamp);
}

и вызов функции:

char teste[50] = "5ABBF13A000A01";
bDecode_HexString(teste);

Я получаю data = 0x3a000a01005abbf1

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Если вы все еще боретесь с разделением входных данных на flags, rate & timestamp, то в комментариях содержатся предложения относительно использования типа без знака для преобразования входной строки в значение и использования точных типов ширины, указанных в * 1002.*, позволит избежать потенциальных проблем, связанных с манипулированием типами со знаком (например, потенциальным расширением знака и т. д.)

Если вы хотите отделить значения и согласовать их в структуре, то это 100%хорошо.Работа состоит в разделении личности flags, rate & timestamp.Как вы решите хранить их так, чтобы они были удобны в вашем коде, решать только вам.Простая структура, использующая тип точной ширины, может быть:

typedef struct {    /* struct holding sensor data */
    uint8_t  flags;
    uint16_t rate;
    uint32_t tstamp;   
} sensor_t;

При преобразовании из char * в uint64_t с strtoull у вас есть две первичные проверки:

  1. использует как указатель на строку для преобразования, так и параметр endptr для проверки того, что цифры действительно были преобразованы (strtoull устанавливает endptr для указания 1 символа после последней преобразованной цифры).Это используется для сравнения endptr с исходным указателем для преобразованных данных, чтобы подтвердить, что преобразование имело место (если никакие цифры не были преобразованы, исходный указатель и endptr будут такими же, а возвращаемое значение будет равно нулю);и

  2. , которые вы установили errno = 0; перед преобразованием, а затем проверьте снова после преобразования, чтобы убедиться, что во время самого преобразования не произошло ошибок.Если strtoull обнаруживает ошибку, значение превышает диапазон и т. Д., errno устанавливается в положительное значение.

  3. (и если у вас есть определенные проверки диапазона, например, вы хотитечтобы сохранить результат в размере, меньшем, чем результат преобразования, например uint32_t вместо uint64_t, необходимо проверить, что конечное значение можно сохранить в меньшем типе)

Простой подход будет следующим:

    uint64_t data = 0;                  /* exact width type for conversion */
    ...
    char *p = argc > 1 ? argv[1] : "0x5ABBF13A000A01",  /* input */
        *endptr = p;                    /* endptr for strtoul validation */
    errno = 0;          /* reset errno */
    ...
    data = strtoull (p, &endptr, 0);    /* convert input to uint64_t */

    if (p == endptr && data == 0) {     /* validate digits converted */
        fprintf (stderr, "error: no digits converted.\n");
        return 1;
    }
    if (errno) {    /* validate no error occurred during conversion */
        fprintf (stderr, "error: conversion failure.\n");
        return 1;
    }
    printf ("data: 0x%" PRIx64 "\n\n", data); /* output conerted string */

Наконец, разделение значения в data на отдельные значения flags, rate & timestamp может быть выполнено с помощью простых сдвигов & ANDS, например,

    sensor_t sensor = { .flags = 0 };   /* declare instance of sensor */
    ...
    sensor.flags = data & 0xFF;                             /* set flags */
    sensor.rate = (data >> CHAR_BIT) & 0xFFFF;              /* set rate */
    sensor.tstamp = (data >> (3 * CHAR_BIT)) & 0xFFFFFFFF;  /* set timestamp */

    /* output sensor struct */
    printf ("sensor.flags : 0x%02" PRIx8 "\nsensor.rate  : 0x%04" PRIx16
            "\nsensor.tstamp: 0x%08" PRIx32 "\n", sensor.flags, sensor.rate,
            sensor.tstamp);

В целом, вы можете сделать что-то похожее на:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <errno.h>
#include <limits.h>

typedef struct {    /* struct holding sensor data */
    uint8_t  flags;
    uint16_t rate;
    uint32_t tstamp;   
} sensor_t;

int main (int argc, char **argv) {

    uint64_t data = 0;                  /* exact width type for conversion */
    sensor_t sensor = { .flags = 0 };   /* declare instace of sensor */
    char *p = argc > 1 ? argv[1] : "0x5ABBF13A000A01",  /* input */
        *endptr = p;                    /* endptr for strtoul validation */
    errno = 0;          /* reset errno */

    data = strtoull (p, &endptr, 0);    /* convert input to uint64_t */

    if (p == endptr && data == 0) {     /* validate digits converted */
        fprintf (stderr, "error: no digits converted.\n");
        return 1;
    }
    if (errno) {    /* validate no error occurred during conversion */
        fprintf (stderr, "error: conversion failure.\n");
        return 1;
    }
    printf ("data: 0x%" PRIx64 "\n\n", data); /* output conerted string */

    sensor.flags = data & 0xFF;                             /* set flags */
    sensor.rate = (data >> CHAR_BIT) & 0xFFFF;              /* set rate */
    sensor.tstamp = (data >> (3 * CHAR_BIT)) & 0xFFFFFFFF;  /* set timestamp */

    /* output sensor struct */
    printf ("sensor.flags : 0x%02" PRIx8 "\nsensor.rate  : 0x%04" PRIx16
            "\nsensor.tstamp: 0x%08" PRIx32 "\n", sensor.flags, sensor.rate,
            sensor.tstamp);

    return 0;
}

Пример использования / Вывод

$ ./bin/struct_sensor_bitwise
data: 0x5abbf13a000a01

sensor.flags : 0x01
sensor.rate  : 0x000a
sensor.tstamp: 0x5abbf13a

Просмотрите все и дайте мне знать, еслиу вас есть дополнительные вопросы.

0 голосов

Здесь у вас есть строка длиной 14, представляющая 7-байтовое значение, состоящее из 14 шестнадцатеричных значений. Рассмотрим этот код, используя strtol, который шестнадцатерично преобразует вашу строку в длинное целое, а затем декодирует ее по цифре.

uint64_t n = strtoul(str, NULL, 16); // Convert to hexadecimal
int flags = n % 0x10;
int refresh_rate = (n / 0x100) % 0x100000;
int timestamp = n / 0x1000000;

Вот тестовый пример (#import <stdlib.h>):

char str[16] = "5ABBF13EE00AFF";
uint64_t n = strtoul(str, NULL, 16); // Convert to hexadecimal

// Use divide and mod to extract digit segment
int flags = n % 0x100;
int refresh_rate = (n / 0x100) % 0x10000;
int timestamp = n / 0x1000000;
// Print timestamp, refresh rate, and flags
printf("%p %p %p", timestamp, refresh_rate, flags);

Ожидаемый результат 0x5abbf13e 0xe00a 0xff, как и ожидалось.

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