Если вы все еще боретесь с разделением входных данных на 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
у вас есть две первичные проверки:
использует как указатель на строку для преобразования, так и параметр endptr
для проверки того, что цифры действительно были преобразованы (strtoull
устанавливает endptr
для указания 1 символа после последней преобразованной цифры).Это используется для сравнения endptr
с исходным указателем для преобразованных данных, чтобы подтвердить, что преобразование имело место (если никакие цифры не были преобразованы, исходный указатель и endptr
будут такими же, а возвращаемое значение будет равно нулю);и
, которые вы установили errno = 0;
перед преобразованием, а затем проверьте снова после преобразования, чтобы убедиться, что во время самого преобразования не произошло ошибок.Если strtoull
обнаруживает ошибку, значение превышает диапазон и т. Д., errno
устанавливается в положительное значение.
(и если у вас есть определенные проверки диапазона, например, вы хотитечтобы сохранить результат в размере, меньшем, чем результат преобразования, например 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
Просмотрите все и дайте мне знать, еслиу вас есть дополнительные вопросы.