简体   繁体   English

将m个字节的数组拆分为n个字节的块

[英]Split array of m bytes into chunks of n bytes

I'm working on a program that manipulates brain data. 我正在研究一种操纵大脑数据的程序。 It recieves a value represents the current magnitude of 8 commonly-recognized types of EEG (brain-waves). 它收到的值代表了8种常见识别类型的脑电图(脑电波)的当前幅度。 This data value is output as a series of eight 3-byte unsigned integers in little-endian format. 该数据值以小端格式输出为一系列8个3字节无符号整数。

Here is a piece of my code: 这是我的一段代码:

    if (extendedCodeLevel == 0 && code == ASIC_EEG_POWER_CODE)     
    {
         fprintf(arq4, "EXCODE level: %d CODE: 0x%02X vLength: %d\n", extendedCodeLevel, code, valueLength );
         fprintf(arq4, "Data value(s):" );
         for( i=0; i<valueLength; i++ ) fprintf(arq4, " %d", value[0] & 0xFF );
      }

The value value[0] is my output. 值[0]是我的输出。 It is the series of bytes that represents the brain waves. 它是代表脑电波的一系列字节。 The current output file contains is the following data: 当前输出文件包含以下数据:

EXCODE level: 0x00  CODE: 0x83 vLength: 24
Data value(s): 16 2 17 5 3 2 22 1 2 1 0 0 0 4 0 0 3 0 0 5 1 0 4 8

What I need is to divide the sequence of bytes above into 3-byte chunks, to identify the EEG. 我需要的是将上面的字节序列分成3个字节的块,以识别EEG。 The wave delta is represented by the first 3-byte sequence, theta is represented by the next bytes, and so on. 波形增量由第一个3字节序列表示,θ由下一个字节表示,依此类推。 How can I do it? 我该怎么做?

Assuming that you know that your input will always be exactly eight three-bit integers, all you need is a simple loop that reads three bytes from the input and writes them out as a four-byte value. 假设您知道您的输入将始终是八个三位整数,您只需要一个简单的循环,从输入读取三个字节并将其写为四字节值。 The easiest way to do this is to treat the input as an array of bytes and then pull bytes off of this array in groups of three. 最简单的方法是将输入视为一个字节数组,然后以三个为一组从该数组中拉出字节。

// Convert an array of eight 3-byte integers into an array
//  of eight 4-byte integers.
void convert_3to4(const void* input, void* output)
{
   uint32_t   tmp;
   uint32_t*  pOut = output;
   uint8_t*   pIn = input;
   int        i;

   for (i=0; i<24; i+=3)
   {
      tmp  = pIn[i];
      tmp += (pIn[i+1] << 8);
      tmp += (pIn[i+2] << 16);
      pOut[((i+2) / 3)] = tmp;
   }
}

Like this? 像这样? The last bytes are not be printed if are not aligned by 3. Do you need them? 如果没有对齐,则不打印最后一个字节。你需要它们吗?

for( i=0; i<valueLength; i+=3 ) fprintf(arq4, "%d %d %d - ", value[i] & 0xFF,
                                                             value[i+1] & 0xFF,
                                                             value[i+2] & 0xFF );

Converting eight 3-byte little endian character-steams into eight 4-byte integers is fairly trivial: 将8个3字节小端字符流转换为8个4字节整数是相当简单的:

for( int i = 0; i < 24; ++i )
{
    output[ i & 0x07 ] |= input[ i ] << ( i & 0x18 );
}

I think that (untested) code will do it. 我认为(未经测试的)代码会这样做。 Assuming input is a 24-entry char array, and output is an eight-entry int array. 假设输入是一个24项char数组,输出是一个八项int数组。

You might try s.th. 你可以试试s.th. like this: 像这样:

union _32BitValue
{
    uint8_t bytes[4];
    uint32_t uval;
}

size_t extractUint32From3ByteSegemented(const std::vector<uint8_t>& rawData, size_t index, uint32_t& result)
{
    // May be do some checks, if the vector size fits extracting the data from it,
    // throwing exception or return 0 etc. ...

    _32BitValue tmp;
    tmp.bytes[0] = 0;
    tmp.bytes[1] = rawData[index + 2];
    tmp.bytes[2] = rawData[index + 1];
    tmp.bytes[3] = rawData[index];

    result = ntohl(tmp.uval);
    return index + 3;
}

The code used to parse the values from the raw data array: 用于解析原始数据数组中的值的代码:

size_t index = 0;
std::vector<uint8_t> rawData = readRawData(); // Provide such method to read the raw data into the vector
std::vector<uint32_t> myDataValues;

while(index < rawData.size())
{
    uint32_t extractedValue;
    index = extractUint32From3ByteSegemented(rawData,index,extractedValue);
    // Depending on what error detection you choose do check for index returned
    // != 0, or catch exception ...
    myDataValues.push_back(extractedValue);
}

// Continue with calculations on the extracted values ...

Using the left shift operator and addition as shown in other answers will do the trick as well. 使用左移运算符和其他答案中显示的加法也可以解决问题。 But IMHO this sample shows clearly what's going on. 但恕我直言,这个样本清楚地显示了正在发生的事情。 It fills the unions byte array with a value in big-endian (network) order and uses ntohl() to retrieve the result in the host machine's used format (big- or little-endian) portably. 它使用big-endian(网络)顺序的值填充联合字节数组,并使用ntohl()以可移植的方式检索主机的使用格式(大端或小端)。

What I need is, instead of displaying the whole sequence of 24 bytes, I need to get the 3-byte sequences separately. 我需要的是,我需要分别获得3字节序列,而不是显示24字节的整个序列。

You can easily copy the 1d byte array to the desired 2d shape. 您可以轻松地将1d字节数组复制到所需的2d形状。

Example: 例:

#include <inttypes.h>
#include <stdio.h>
#include <string.h>

int main() {
    /* make up data */
    uint8_t bytes[] = 
        { 16,  2, 17, 
           5,  3,  2, 
          22,  1,  2,
           1,  0,  0,
           0,  4,  0, 
           0,  3,  0,
           0,  5,  1,
           0,  4,  8 };
    int32_t n_bytes = sizeof(bytes);
    int32_t chunksize = 3;
    int32_t n_chunks = n_bytes/chunksize + (n_bytes%chunksize ? 1 : 0);

    /* chunkify */
    uint8_t chunks[n_chunks][chunksize];
    memset(chunks, 0, sizeof(uint8_t[n_chunks][chunksize]));
    memcpy(chunks, bytes, n_bytes);

    /* print result */
    size_t i, j;
    for (i = 0; i < n_chunks; i++)
    {
        for (j = 0; j < chunksize; j++)
            printf("%02hhd ", chunks[i][j]);
        printf("\n");
    }
    return 0;
}

The output is: 输出是:

16 02 17 
05 03 02 
22 01 02 
01 00 00 
00 04 00 
00 03 00 
00 05 01 
00 04 08

I used some of the examples here to come up with a solution, so I thought I'd share it. 我在这里使用了一些例子来提出解决方案,所以我想我会分享它。 It could be a basis for an interface so that objects can transmit copies of themselves over a network with the hton and ntoh functions, which is actually what I am trying to do. 它可以是一个接口的基础,这样对象就可以通过网络传输hton和ntoh函数的副本,这实际上就是我想做的事情。

#include <iostream>
#include <string>
#include <exception>
#include <arpa/inet.h>



using namespace std;

void DispLength(string name, size_t var){
    cout << "The size of " << name << " is : " << var << endl;
}


typedef int8_t byte;

class Bytes {
public:
    Bytes(void* data_ptr, size_t size)
    : size_(size)
    { this->bytes_ = (byte*)data_ptr; }


    ~Bytes(){ bytes_ = NULL; } // Caller is responsible for data deletion.


    const byte& operator[] (int idx){
        if((size_t)idx <= size_ && idx >= 0)
            return bytes_[idx];
        else
            throw exception();
    }


    int32_t ret32(int idx) //-- Return a 32 bit value starting at index idx
    {
        int32_t* ret_ptr = (int32_t*)&((*this)[idx]);
        int32_t  ret     = *ret_ptr;
        return ret;
    }


    int64_t ret64(int idx) //-- Return a 64 bit value starting at index idx
    {
        int64_t* ret_ptr = (int64_t*)&((*this)[idx]);
        int64_t  ret     = *ret_ptr;
        return ret;
    }


    template <typename T>
    T retVal(int idx) //-- Return a value of type T starting at index idx
    {
        T* T_ptr = (T*)&((*this)[idx]);
        T  T_ret = *T_ptr;
        return T_ret;
    }

protected:
    Bytes() : bytes_(NULL), size_(0) {}


private:
    byte* bytes_; //-- pointer used to scan for bytes
    size_t size_;
};

int main(int argc, char** argv){
    long double LDouble = 1.0;
    Bytes bytes(&LDouble, sizeof(LDouble));
    DispLength(string("LDouble"), sizeof(LDouble));
    DispLength(string("bytes"), sizeof(bytes));
    cout << "As a long double LDouble is " << LDouble << endl;
    for( int i = 0; i < 16; i++){
        cout << "Byte " << i << " : " << bytes[i] << endl;
    }
    cout << "Through the eyes of bytes : " <<
            (long double) bytes.retVal<long double>(0) << endl;
    return 0;
}

you can use bit manipulation operators 你可以使用位操作运算符

I would use, not following actual code, just show example 我会使用,而不是按照实际代码,只显示示例

(for I =0 until 7){ (对于I = 0到7){

temp val = Value && 111 //AND operation with 111 temp val = Value && 111 // AND操作111

Value = Value >> 3; 值=值>> 3; //to shift right //向右移

} }

Some self documenting, maintainable code might look something like this (untested). 一些自我记录,可维护的代码可能看起来像这样(未经测试)。

typedef union
{
    struct {
        uint8_t padding;
        uint8_t value[3];
    } raw;
    int32_t data;
} Measurement;

void convert(uint8_t* rawValues, int32_t* convertedValues, int convertedSize)
{
    Measurement  sample;
    int          i;

    memset(&sample, '\0', sizeof(sample));

    for(i=0; i<convertedSize; ++i)
    {
        memcpy(&sample.raw.value[0], &rawValues[i*sizeof(sample.raw.value)], sizeof(sample.raw.value));
        convertedValues[i]=sample.data;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM