Извлечение данных из двоичного потока данных в nsdata - PullRequest
1 голос
/ 15 апреля 2011

В данный момент я новичок в цели c и пытаюсь декодировать поток данных, который получаю как объект NSdata.

данные имеют длину 8 байт, например:

 1               2               3               4               
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  code1        |code2  |   code3               | code4         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

 5               6               7               8              
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                           code5                                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Из массива nsdata, как я могу легко вывести разные коды, учитывая, что code3 не находится на границе байтов?

Я пробовал подобные этому:

NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);

однако не может заставить его работать должным образом с различными границами. Извинения, если это кажется немного расплывчатым, могут подтвердить детали, если это необходимо

1 Ответ

2 голосов
/ 15 апреля 2011

То, что вы делаете, выглядит отлично - в чем проблема?Можете ли вы получить данные в свой указатель byteData?Если это так, то между target-c, C или чем-то еще не отличается (и NSData тогда не очень хороший тег) - вам просто нужно получить битовый доступ к вашим байтам.

Этого можно достичь, создавструктура с такими определениями битовых полей (псевдокод, битовое поле Google)

struct 
{
 char byte1;
 char a3bitfield : 3;
 char a5bitfield : 5;
 char byte3;
}

Или с использованием битовых масок, или с помощью сдвигов.


Изменить в ответ на комментарий:

Это показывает, как сделать сдвиг

Первая проблема, которую вы собираетесь иметь в том, чтовы показываете свои биты слева направо, что в системах с прямым порядком байтов не является точным, вы должны думать о битах как о:

7 6 5 4 3 2 1 0

Вместо

0 1 2 3 4 5 6 7

В противном случае вы никогда не поймете, как будут работать направления маскирования и сдвига.

При условии, что у вас разбиты байты, как вам кажется, и вы знаете, с каким байтом вы работаете, байт x:

7 6 5 4 3 2 1 0 [5 бит a] [3 бита b]

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

char onlya = ((x & 11111000b) >> 3);

Что означает, что я хочу использовать эти старшие 5 бит a и отбросить младшие 3 бита, а затем сдвиньте все 3 бита вправо для компенсации.Если вы начали с: AAAAABBB, где A - это данные из a, а B - это данные из B, которые вас не интересуют, то «x & 11111000b» приведет к: AAAAA000, а последующее >> 3 приведет к: 000AAAAA

В тех случаях, когда А смещается вправо, вводя 0 там, где были пробелы, и отбрасывая 0 справа.

Таким образом, чтобы в этом случае получить В в одиночку, вам нужно только сделать следующее:

char onlyb = (x & 00000111b);

Сдвиг не требуется.

Если вы работаете за битовыми границами с 2 байтами N и M, такими как:

NM 7 6 5 4 3 2 1 07 6 5 4 3 2 1 0 XXXXAAAAAAAXXXXX

Вы бы сделали:

char merged = 0;
merged |= (N & 00001111b) << 3;
merged |= (M & 11100000b) >> 5;

Я маскируюсь, чтобы получить только A от N и M, а затем я перехожу кРЕЗУЛЬТАТЫ МЕСТО.Так что, когда я закончу с этими 3 шагами по порядку, результат слияния будет:

merged = 0 дает: 0 0 0 0 0 0 0 0

Первое слияние | =дает: 0 NNNN 0 0 0

Второе объединение | = дает: 0 NNNNMMM

В этот момент вы действуете с вашими данными, как обычно (преобразование в int или что-либо еще)

И, как я уже сказал, альтернатива - битовые поля

...