nanopb中的编码和解码问题

问题描述

最近开始研究nanopb-如果我的问题听起来很傻,就道歉。修改nanopb的简单示例时,我在分配和检索字符串和整数时遇到一些问题。让我先回答我的问题-

  1. 我定义了simple.proto文件
message Device{
optional string devid =1; 
optional string mac = 2; 
optional string cpu=3 [default = "x86"] ; 
optional bool isSecured=4;
optional int32 uptime = 5 [default = 1234];
}

  1. 还定义了simple.option
Device.devid max_size:64
Device.cpu max_size:64

然后我像往常一样编译:protoc -osimple.pb simple.proto

  1. 这是我的代码

3a)使用与How to encode a string when it is a pb_callback_t type

中相同的字符串编码解码实用程序功能
//string encode decode to pb
bool encode_string(pb_ostream_t* stream,const pb_field_t* field,void* const* arg)
{
    const char* str = (const char*)(*arg);

    if (!pb_encode_tag_for_field(stream,field))
        return false;

    return pb_encode_string(stream,(uint8_t*)str,strlen(str));
}

bool print_string(pb_istream_t *stream,const pb_field_t *field,void **arg)
{
    uint8_t buffer[1024] = {0};

    /* We Could read block-by-block to avoid the large buffer... */
    if (stream->bytes_left > sizeof(buffer) - 1)
        return false;

    if (!pb_read(stream,buffer,stream->bytes_left))
        return false;

    /* Print the string,in format comparable with protoc --decode.
     * Format comes from the arg defined in main().     */
    printf((char*)*arg,buffer);
    return true;
}

3b)这是我基于示例simple.c的主要代码段-

    /* This is the buffer where we will store our message. */
    uint8_t buffer[128];
    size_t message_length;
    bool status;

    /* Encode our message */
    {
        /* Allocate space on the stack to store the message data,check out the contents of simple.pb.h
         * good to always initialize your structures so that no garbage data from RAM in there.   */

        //Device message = Device_init_zero;   //init zero   for empty
        Device message = Device_init_default;  //init default for default

        /* Create a stream that will write to our buffer. */
        pb_ostream_t stream = pb_ostream_from_buffer(buffer,sizeof(buffer));

        /* Fill in the data */
        message.devid.arg = "device1";
        message.devid.funcs.encode = &encode_string;


        //strcpy(message.devid,"device1");  // no easier way like this ?

        message.isSecured = true;   // should be 1 if printed with %d
        message.uptime=9876;        // should change,why it is not working ?

        /* Now we are ready to encode the message! */
        // encode stream to buffer,also get the buffer length
        status = pb_encode(&stream,Device_fields,&message);
        message_length = stream.bytes_written;

        /* Then just check for any errors.. */
        if (!status)
        {
            printf("Encoding Failed: %s\n",PB_GET_ERROR(&stream));
            return 1;
        }
    }

    /* Now we Could transmit the message over network,store it in a file etc.   */
    /* just decode it immediately. */
    {
         /* Allocate space for the decoded message. */
        Device message = Device_init_zero;

        /* Create a stream that reads from the buffer. */
        pb_istream_t stream = pb_istream_from_buffer(buffer,message_length);

        message.devid.funcs.decode = &print_string;
        message.devid.arg = "before decode Device - devid: %s \n"; //works here

        message.cpu.funcs.decode = &print_string;
        message.cpu.arg = "before decode Device -cpu: %s \n";   //where in op?

        printf("before decode isSecured %d\n",message.isSecured);  // doesn't work
        
        printf("before decode uptime %d\n",message.uptime); //doesn't work

        /* Now ready to decode the message. */
        // decode  stream buffer into message
        status = pb_decode(&stream,&message);

        /* Check for errors... */
        if (!status)
        {
            printf("Decoding Failed: %s\n",PB_GET_ERROR(&stream));
            return 1;
        }

        /* Print the data contained in the message. */
        
        message.devid.funcs.decode = &print_string;
        message.devid.arg = "after decode Devic - devid: %s \n";  // doesn't work here

        printf(" after decode isSecured %d\n",message.isSecured);  // prints default 0        

    printf(" after decode uptime %d\n",(int)message.uptime);   //prints default assigned in proto
    }
  1. 构建并运行后的输出
$ ./simple
before decode isSecured 0
before decode uptime 0
before decode Device - devid: device1
 after decode isSecured 0
 after decode uptime 1234

我的查询(还在代码添加了我的内联注释):

  1. 在原始的simple.c中,message.lucky_number = 13分配有效,但这里的message.uptime分配不起作用,它采用认值。同样,将布尔值分配给message.isSecured无法正常工作。请告诉我我的错在哪里。
  2. 我在pb_encode之前使用Device_init_default,因为有些具有认值,在pb_decode调用之前使用Device_init_zero,因为它将在解码后填充。我的方法正确吗?
  3. 除了encode_string和decode_string util之外,还有没有更简单的方法使用strcpy分配字符串值并通过printf(“%s”,strvar)以C方式打印它?
  4. 仅在调用pb_decode之前打印字符串,但是在调用pb_decode之后打印正常运行时间认值。布尔值分配也不起作用。为什么呢我怎么了?
  5. 我在https://github.com/nanopb/nanopb/blob/master/tests/callbacks/encode_callbacks.c中看到了编码字符串和int函数 如何对float和boolean进行编码和解码?

感谢您的期待

解决方法

  1. 在原始的simple.c中,message.lucky_number = 13分配有效,但这里的message.uptime分配不起作用,它采用默认值。同样,将布尔值分配给message.isSecured无法正常工作。请告诉我我的错在哪里。

如果查看生成的.pb.h文件,您会发现每个可选字段都有一个布尔值has_field。您还必须将其设置为true,以表示该字段存在。

  1. 我在pb_encode之前使用Device_init_default,因为有些具有默认值,在pb_decode调用之前使用Device_init_zero,因为它将在解码后填充。我的方法正确吗?

很好。

  1. 除了encode_string和decode_string util之外,还有没有更简单的方法使用strcpy分配字符串值并通过printf(“%s”,strvar)以C方式打印它?

由于您已经为字符串字段设置了max_size,因此应该将它们生成为char数组而不是回调。您可以尝试传递-v之类的../generator/nanopb_generator.py -v simple.pb开关,以查看更多详细消息,这些消息可以指出为什么不应用该选项。可能是文件名不正确或消息名称不正确。

仅在调用pb_decode之前打印字符串,但是在调用pb_decode之后打印正常运行时间默认值。布尔值分配也不起作用。为什么呢我怎么了?

我在https://github.com/nanopb/nanopb/blob/master/tests/callbacks/encode_callbacks.c中看到了编码字符串和int函数的方法如何编码和解码float和boolean?

好吧,通常您不必诉诸回调。但是,如果您决定需要它们,则可以使用pb_encode_varint()编码布尔值,并使用pb_encode_fixed32()浮动值。对于研究回调,protobuf encoding documentationthis test case可能会有所帮助。


您可能会发现network_server示例对学习很有帮助。

此外,当每个帖子只有一个问题时,堆栈溢出格式最有效。这样,问题和答案就可以保持重点突出并且易于理解。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...