【问题标题】:Split unsigned char array into array of multiple unsigned char array将 unsigned char 数组拆分为多个 unsigned char 数组的数组
【发布时间】:2021-12-06 02:25:43
【问题描述】:

我的应用程序由一个控制器组成,该控制器有几个孩子。控制器使用管道与之通信的是第一个孩子,孩子使用我们之间的管道将问题传递给下一个兄弟。当一个孩子可以处理这个问题时,它会向控制器管道发送一个帧以宣告无罪。

我的问题是因为每个孩子都可以在控制器管道中写入,控制器可能会在同一流中读取多个孩子的帧。

所以,我想拆分这个流来处理子框架个体。

控制器只接收一种类型的帧:

Acquittal Frame
0                 1                 2                 3
 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       CMD       |     NODE ID     |    ERROR FLAG   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      DATA LENGTH (optional)       |                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                 |
|   DATA WITH UNDETERMINED SIZE (char *) (optional)   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    END FRAME    |
+-+-+-+-+-+-+-+-+-+

这个框架是由多个信息组成的:

  • CMD : 对控制者说孩子回答哪个问题的无罪建议
  • NODE ID:孩子的唯一标识符
  • 错误标志:在结果和命令的函数中可以有不同的值

命令:

  • A_SET(0xA2):
    • 此命令只承认 2 个错误标志 SUCCESS(0x20) 和 INTERNAL_ERROR(0x50)
    • 使用此 cmd,帧大小为 4,无数据长度和数据
  • A_DUMP(0xD2):
    • 此命令只承认 2 个错误标志 SUCCESS(0x20) 和 INTERNAL_ERROR(0x50)
    • 使用此 cmd,帧大小为 4,无数据长度和数据
  • A_LOOKUP(0xB2):
    • 如果此命令具有错误标志 INTERNAL_ERROR(0x50) 或 NOT_FOUND(0x44),则帧大小将为 4
    • 如果此命令有错误标志 SUCCESS(0x20),则帧大小将为 4 + DATA LENGTH,编码为两个字节

所以以我为例,我想要这个:

{0xd2,0x04,0x20,0x04,0xd2,0x05,0x20,0x04,0xd2,0x06,0x20,0x04,0xd2,0x07,0x20,0x04,0xb2,0x08,0x20,0x01,0x08,0x62,0x6f,0x6e,0x6a,0x6f,0x75,0x72,0x04}

我想提取一个看起来像这样的数组:

[0] : {0xd2,0x04,0x20,0x04}
[1] : {0xd2,0x05,0x20,0x04}
[2] : {0xd2,0x06,0x20,0x04}
[3] : {0xd2,0x07,0x20,0x04}
[4] : {0xb2,0x08,0x20,0x01,0x08,0x62,0x6f,0x6e,0x6a,0x6f,0x75,0x72,0x04}

我尝试了多种方法来做到这一点:手动阵列跑酷,strtok() 功能。 所以,我在这里向你展示 stork 函数的最后一次尝试:

enum frameComponents {
    END_FRAME=(unsigned char)0x04,
    ...
}
...

unsigned int getNbFrames(unsigned char * framesStream){
    unsigned int lenFrames = strlen((char * )framesStream);
    unsigned int i,k;
    for(i=0,k=0;i<lenFrames;i++){
        if(framesStream[i]==END_FRAME){
            k++;
        }
    }
    return k;
}


unsigned char ** deserialisation(unsigned char * frameStream){
    //this function return the number of identify frame in the stream
    unsigned int nbFrame = getNbFrames(frameStream);
    unsigned int lenFrames = strlen((char * )frameStream);
    unsigned char **framesArray = malloc(nbFrame * sizeof(unsigned char *));
    unsigned char *tempFrameStream = malloc(sizeof(unsigned char)*lenFrames+1);
    unsigned char * extractedFrame = (unsigned char *) strtok(tempFrameStream, (char *)END_FRAME);
    strcpy((char *)tempFrameStream,(char *) frameStream);
    int i = 0;
    while(extractedFrame != NULL ) {
        extractedFrame = (unsigned char *) strtok(NULL, (char *)END_FRAME);
        framesArray[i]= malloc(strlen((char *)extractedFrame)+1);
        strcpy((char *)framesArray[i],(char *)extractedFrame);
        i++;
    }
    free(tempFrameStream);
    free(extractedFrame);
    return framesArray;
}

但是我这里有很多问题

首先,strtok() 似乎无法正常工作,因为当我尝试使用一个字符串时,我的数组中有 null 返回。我不知道这是否来自我的数组的 unsigned int 类型?

其次,当我尝试访问函数外部的帧数组时,出现分段错误。即使在我的数组中有 malloc()

【问题讨论】:

  • uint8_t *p = original_array, *end = original_array + size_of_original_array; for (unsigned i = 0; p &lt; end; ++i) { memcpy(destination_array[i], p, 4); p += 4; }?或类似的东西。
  • 我已经展示了一个简单的例子,但是一个框架可能会以未知的大小到达。例如,我可以有这个传入流:a2-3-20-4-b2-8-20-1-8-62-6f-6e-6a-6f-75-72-4,所以在这种情况下,我需要 return[0] 为 a2-3-20-4 并且 return[1] 为 b2-8-20-1-8-62-6f-6e-6a-6f-75-72-4
  • (char *)END_FRAME 肯定不是你想要的
  • strlen 在这种情况下可以工作吗?看起来您的 char 数组不是以空值结尾的。
  • 是的,你所拥有的是一个无符号字符流。这不是字符串,因此您不能使用strlen。因此,您需要从从管道读取的函数中获取“流大小”

标签: arrays c segmentation-fault char


【解决方案1】:

由于您的输入数据不是字符串而是原始字节流(也称为无符号字符流),因此您不能将字符串函数用于解码器。

您需要实现一个将协议考虑在内的解析器,即您需要查看每一帧并查看它是什么命令。一旦你知道了命令,你就可以相应地解析数据。

我不会为您实现完整的解析器,但下面是一些显示主体的代码。代码不会将帧放入分配的内存中(我将把它留给您),代码只是打印帧(在 3 种情况下的 2 种情况下,我将留给您实现的最后一种情况。

#define A_SET (0xA2)
#define A_DUMP (0xD2)
#define A_LOOKUP (0xB2)

void deserialisation(unsigned char * frameStream, size_t n)
{
    size_t index = 0;
    while (index < n)
    {
        switch(frameStream[index])
        {
            case A_SET:
                if (index + 4 > n)
                {
                    puts("Too little data! can't continue...");
                    index = n;
                }
                else
                {
                    // Good frame - just print it for now
                    printf("A_SET cmd: ");
                    for (size_t i = 0; i < 4; ++i) printf("0x%02X ", frameStream[index + i]);
                    puts("");
                    index += 4;
                }
                break;
                
            case A_DUMP:
                if (index + 4 > n)
                {
                    puts("Too little data! can't continue...");
                    index = n;
                }
                else
                {
                    // Good frame - just print it for now
                    printf("A_DUMP cmd: ");
                    for (size_t i = 0; i < 4; ++i) printf("0x%02X ", frameStream[index + i]);
                    puts("");
                    index += 4;
                }
                break;
                
            case A_LOOKUP:
                printf("A_LOOKUP cmd: ");
                // Add code here...
                break;
                
            default:
                puts("Unknow frame! Can't continue...");
                index = n;
                break;
        }
    }
}
    
int main(void)
{
    unsigned char pipeData[] = {0xA2, 0x01, 0x20, 0x04, 0xD2, 0x14, 0x50, 0x04};
    deserialisation(pipeData, sizeof pipeData / sizeof pipeData[0]);
    return 0;
}

输出:

A_SET cmd: 0xA2 0x01 0x20 0x04 
A_DUMP cmd: 0xD2 0x14 0x50 0x04 

【讨论】:

    猜你喜欢
    • 2013-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多