Nanopb技术问询:如何定义包含自嵌套类型的消息?
Nanopb自嵌套消息递归错误解决(保留string字段has_标记)
问题重现
正常非嵌套场景
当消息不包含自嵌套字段时,使用全局max_size配置可以正常生成代码,且会为每个optional string字段生成has_xxx标记:
syntax = "proto2"; import "nanopb.proto"; option (nanopb_fileopt).max_size = 20; message myMessage { optional string string1 = 1; optional string string2 = 2; optional string string3 = 3; }
生成的C结构体:
typedef struct _myMessage { bool has_string1; char string1[20]; bool has_string2; char string2[20]; bool has_string3; char string3[20]; /* @@protoc_insertion_point(struct:myMessage) */ } myMessage;
自嵌套场景报错
添加自嵌套字段后,代码生成触发无限递归错误:
syntax = "proto2"; import "nanopb.proto"; option (nanopb_fileopt).max_size = 20; message myMessage { optional string string1 = 1; optional string string2 = 2; optional string string3 = 3; optional myMessage submessage = 4; }
错误信息:
$ python3 generate_c_files.py test/aaa.proto Today is a good day to code Traceback (most recent call last): File ".../generator/nanopb_generator.py", line 1850, in <module> main_cli() File ".../generator/nanopb_generator.py", line 1746, in main_cli results = process_file(filename, None, options) File ".../generator/nanopb_generator.py", line 1704, in process_file headerdata = ''.join(f.generate_header(includes, headerbasename, options)) File ".../generator/nanopb_generator.py", line 1338, in generate_header msize = msg.encoded_size(self.dependencies) File ".../generator/nanopb_generator.py", line 1068, in encoded_size fsize = field.encoded_size(dependencies) File ".../generator/nanopb_generator.py", line 670, in encoded_size encsize = submsg.encoded_size(dependencies) ... RecursionError: maximum recursion depth exceeded in __instancecheck__
原因分析
全局(nanopb_fileopt).max_size会触发Nanopb生成器计算整个消息的最大编码大小,而自嵌套结构会导致生成器无限递归计算子消息的大小,最终超出Python递归深度限制。同时,C语言本身不允许结构体直接包含自身实例,这也是后续需要解决的潜在问题。
解决方案
1. 用字段级max_size替代全局配置
将string字段的max_size设置从全局文件级改为字段级,避免触发全局消息大小计算:
syntax = "proto2"; import "nanopb.proto"; message myMessage { optional string string1 = 1 [(nanopb).max_size = 20]; optional string string2 = 2 [(nanopb).max_size = 20]; optional string string3 = 3 [(nanopb).max_size = 20]; optional myMessage submessage = 4; }
2. 为自嵌套字段指定指针类型(必做)
C语言不允许结构体直接包含自身,因此需要为自嵌套字段设置指针类型,并可同时指定其最大编码大小避免递归:
syntax = "proto2"; import "nanopb.proto"; message myMessage { optional string string1 = 1 [(nanopb).max_size = 20]; optional string string2 = 2 [(nanopb).max_size = 20]; optional string string3 = 3 [(nanopb).max_size = 20]; optional myMessage submessage = 4 [(nanopb).type = FT_POINTER, (nanopb).max_size = 100]; }
生成的正确代码示例
修改后生成的C结构体将包含has_xxx标记,且自嵌套字段为指针类型:
typedef struct _myMessage { bool has_string1; char string1[20]; bool has_string2; char string2[20]; bool has_string3; char string3[20]; bool has_submessage; struct _myMessage *submessage; /* @@protoc_insertion_point(struct:myMessage) */ } myMessage;
内容的提问来源于stack exchange,提问作者Charlene
相关产品推荐
相关产品推荐

