LINUX.ORG.RU

Старший бит в битовом поле для целого

 


2

3

Добрый день! Думаю как правильнее сделать обработку такой структуры. Имеет цклое число из 9 бит с неправильным порядком байтов. При этом оно разбивается на две части - первая (i9m_1) размером в один бит. Тут лежит знак. Во второй (i9m_0) младшая часть. Все работает, но компилятор ругается на i9m_1 «warning #109-D: signed bit field of length 1» Можно, конечно, запретить варнинг, но мне не нравится. Как правильнее обрабатывать такие ситуации?

#pragma pack(push,1)
typedef struct {
    int16_t i9m_1:1;
    uint8_t _reserved_25:7;
    uint8_t i9m_0;
#endif
} wire_TEST_MSG_2_t;

#define _GET_8_i09(signal) (signal##_0 | (( int16_t)signal##_1 << 8))

//Получаем значение
int16_t value = (int16_t)_GET_8_i09(wire_data->i9m);

#pragma pack(pop)

★★★

Может компилятор тебе тонко намекает, что битовое поле из одного бита ну никак не может иметь знак и тебе стоит поставить uint16_t?

pon4ik ★★★★★
()

Ты наркоман. Сделай по-человечески, без структур и жутких макросов. Примерно так:

int i9m_1 = read_u8() >> 7;
int i9m_0 = read_u8();
int value = i9m_1 ? i9m_0 : -i9m_0;
anonymous
()

#define _GET_8_i09(signal)

Судя по этому делаю вывод, что ты хочешь сделать обработку сигнала в фиксед поинт числах. Но зачем так усложнять? К тому же еще и неэффективно? Пакование структур, структуры? Почитай про Q формат чисел, все уже придуманно до нас.

Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

Это мне так приходит по сети. 9 бит в bigendian формате

vromanov ★★★
() автор топика
Ответ на: комментарий от anonymous

У меня таких макросов >7000 строк. Для разной длинны переменной и положения первого бита. Но можно будет сделать такой вариант специально для случая когда число знаковое и первый кусочек в один бит.

vromanov ★★★
() автор топика

Однобитовые поля надо делать unsigned; но с битовыми полями лучше вообще не связываться, если не можешь в любое время дня и ночи назвать порядок битовых полей при заданном сочетании компилятора и архитектуры :)

tailgunner ★★★★★
()

Уж сколько раз твердили миру - распаковывый то что «приходит по сети» из байт сдвигами и бинарными операциями, забудь про битовые поля и pragma pack.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

то, что ты выше расписал про сдвиги и прочее. стандартные функции используют настройки текущей архитектуры и в норме не надо ничего никуда сдвигать и менять порядок вручную.

Iron_Bug ★★★★★
()
Ответ на: комментарий от slovazap

утверждение было голословно и не привязано к 9 битам. но даже с 9 битами: и с чего это там битовые поля в упакованных структурах не подошли?

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от Iron_Bug

Попробуй ответить на простой вопрос: какая стандартная функция разберёт тебе 9 бит в знаковое целое?

используют настройки текущей архитектуры

Если что, разбор байтового потока никак не зависит от текущей архитектуры.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

я про то, что не надо оперировать терминами «вообще», «все», «всегда» и прочее такое. битовые структуры прекрасно используются в харде, где полно всяких нестандартных форматов.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

Чтобы говорить что «надо» и «не надо», нужно сначала быть компетентным в обсуждаемом вопросе.

slovazap ★★★★★
()
Ответ на: комментарий от Iron_Bug

Надо!

Вот примеры структур, которые надо разбирать. Из интересного, они содержат поля и в бигэендиан и в литлэндиан формате. И разбирать их надо на обоих архитектурах (BE & LE):

Собственно это у меня уже есть. Остался один косячок с этим битиком.

vromanov ★★★
() автор топика
Последнее исправление: vromanov (всего исправлений: 1)
Ответ на: комментарий от vzzo

Непрерывно :). Но, например, на PowerPC. А читать надо на интеле

vromanov ★★★
() автор топика
Ответ на: комментарий от beastie

те, поля название которых заканчивается на i (intel) - LE, m (motorola) - BE. Например test_msg_0 - все LE. А tst_msg_2 содержит и те, и те. Случай редкий, но на всякий случай хочется его предусмотреть.

vromanov ★★★
() автор топика
Ответ на: комментарий от vromanov

А по-моему нет. Они разнесенны в адрессном пространстве, но всё же все поля NBO (msg2):

  • синее: ntohl(((data[1]&15)<<2)|((data[2]&3)>>6))
  • зелёное: ntohl(((data[3]&1)<<8)|data[4])
  • оранжевое: ntohl(((data[6]&1)<<8))|data[5])

И если честно, я бы их так и шинковал.

PS: хотя, глянув на другие сообщения, может быть я и не прав... меня смущает немного розовое и синее поле в msg1 — биты все nbo, а вот порядок байт (кусков) — фиг знает.

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 2)
Ответ на: комментарий от beastie

С распаковкой/упаковкой у меня проблем нет. Есть описание все этих структур в специальном формате и есть кодогенератор, который генерит структуры и код для парсинга в обе стороны на обоих платформах. И это работает. Волнует именно один бит.

vromanov ★★★
() автор топика
Ответ на: комментарий от beastie

Там же нарисованы стрелочки и даже подписан MSB (Most Significant Bit). Например, зеленое - ntohl не нужен. В 3 байте и так старший бит. Другое дело, что если в этом бите -1 то надо заполнить 1 все остальные старшие биты. А приведенные операции с байтами это не делают.

vromanov ★★★
() автор топика

Не совсем по теме, но вдруг пригодится... А у тебя такое хитрое число одно, или дофига других двоичных данных для чтения? Если вдруг последнее, то не хочешь ли посмотреть в сторону Kaitai Struct?

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

Это CAN шина. И большинсто таких структур придумываем не мы, а производитель. Есть текстововое описание вида

BO_ 2147501122 TEST_MSG_2: 8 Vector__XXX
 SG_ i9m : 24|9@0- (1,0) [0|0] "" Vector__XXX
 SG_ i9i : 40|9@1- (1,0) [0|0] "" Vector__XXX
 SG_ u6m : 11|6@0+ (1,0) [0|0] "" Vector__XXX

«24|9@0-» расшифровывается так - Начинается с бита 24, длинна 9 бит, 0-интел, знаковое.

vromanov ★★★
() автор топика
Последнее исправление: vromanov (всего исправлений: 1)
Ответ на: комментарий от vromanov

Такое ощущение, что вы озадачены обеспечением собственной job security, нежели решением проблемы. Поскольку код на макросах и на битовых полях кроме вас вряд ли кто-то сможет сопровождать.

В самих описаниях сообщений протокола нет ничего сложного. Если эти данные нужно распаковать в какие-то нормальные структуры для работ с ними в программе, то все это делается элементарно: берем n бит из текущего байта, добавляем к ним k бит из следующего байта, потом еще m бит из следующего байта и т.д. Никакой завязки на endianess и порядок расположения битовых полей в вашем компиляторе на вашей архитектуре.

eao197 ★★★★★
()

Считается, что знаковое однобитное целое не имеет смысла, нет таких задач, для которых оно понадобится. Нафига целое с диапазоном значений (-1, 0)? Но если мне понадобится, то я выключу это предупреждение. Но MISRA и др. требования? А как на счет того, что тебе прилетает 9-ти битовое знаковое число, а не однобитовое? На мой взгляд, в данном случае надо сначала вычитать все байты, привести их порядок к нужному, сдвинуть и расширить знаковый бит. А у тебя начинается со знака, а потом склеивается. Это не красиво.

Я б так запилил, конечно memcpy еще добавить вместо тупого приведения типа и присвоения, отвязать от gcc и посолить C++ по вкусу:

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

#define u6m_SWAB
#define u6m_OFFSET 1
#define u6m_SHIFT  6
#define u6m_BITS   6
#define u6m_SIZE   16
#define u6m_TYPE   uint16_t
#define u6m_UTYPE  uint16_t

#define i9m_SWAB   be16toh
#define i9m_OFFSET 3
#define i9m_SHIFT  0
#define i9m_BITS   9
#define i9m_SIZE   16
#define i9m_TYPE   int16_t
#define i9m_UTYPE  uint16_t

#define i9i_SWAB   le16toh
#define i9i_OFFSET 5
#define i9i_SHIFT  0
#define i9i_BITS   9
#define i9i_SIZE   16
#define i9i_TYPE   int16_t
#define i9i_UTYPE  uint16_t

#define GET(d, f) ({\
        union {\
            struct {\
                f##_TYPE a:f##_BITS;\
            } a;\
            f##_UTYPE b;\
        } t;\
        t.b = f##_SWAB(*(f##_UTYPE*)((uint8_t*)(d) + f##_OFFSET)) >> f##_SHIFT;\
        t.a.a;})

int main () {
    uint8_t a[] = {1,2,3,4,5,6,7,8,9,10};
    printf ("%d\n", (int)GET (a, i9m));
    printf ("%d\n", (int)GET (a, i9i));
    printf ("%d\n", (int)GET (a, u6m));
}

fopen ★★
()
Ответ на: комментарий от vromanov

Ну я же написал «примерно». Последнее выражение вполне может быть другое, в зависимости от представления числа (из твоих «абстрактных» примеров ничего не ясно). Приведи несколько конкретных примеров, например вот такие два байта передаются по сети, на выходе должно быть такое-то число.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.