Repeated message field in c pacakge

378 views
Skip to first unread message

osis...@gmail.com

unread,
Nov 25, 2008, 11:54:40 AM11/25/08
to Protocol Buffers
Hi,

I'm using the protocol buffers package for c. It's very useful and
handy. However I've encountered a problem when trying to use a message
with a nested repeated field of an other message type.

This is the simplified version -
message Item {
int32 id = 1;
}

message LookupReply {
repeated Item replica_list = 1;
}

Here is the code for constructing the message:
...
LookupReply nlr = LOOKUP_REPLY__INIT;

(&nlr)->replica_list = (Item**)malloc(1*sizeof(Item*));
(&nlr)->n_replica_list = 1;

Item* item1 = (Item*)malloc(sizeof(Item));
item1->id = 1;
(&nlr)->replica_list[0] = item1;

int len = lookup_reply__get_packed_size(nlr);
...

The call to lookup_reply__get_packed_size causes a segmentation
fault.
I first tried using a string id field in the Item message, and that
failed too.

However when I used a string repeated field (with a few obvious
semantic changes) everything worked fine.

Anyone else has maybe used repeated message field in the c package and
got it to work (or if not, can explain why it doesn't work)?

Thank you,
Aviad

Kenton Varda

unread,
Nov 25, 2008, 2:08:10 PM11/25/08
to osis...@gmail.com, daveb, Protocol Buffers
cc'ing Dave Benson, who maintains the only C port I'm aware of.

daveb

unread,
Nov 27, 2008, 10:42:17 PM11/27/08
to Protocol Buffers
The reason why it is crashing is that all messages have a few builtin
members that are usually initialized via ITEM__INIT. If you look at
the generated Item it looks like:
struct _Item
{
ProtobufCMessage base_message;
uint32_t id;
};
The best way to construct a message is to use C's assignment
operator. Rewriting your code strictly:
LookupReply nlr = LOOKUP_REPLY__INIT;
Item item = ITEM__INIT;

(&nlr)->replica_list = (Item**)malloc(1*sizeof(Item*));
(&nlr)->n_replica_list = 1;

Item* item1 = (Item*)malloc(sizeof(Item));
item.id = 1;
*item1 = item;
(&nlr)->replica_list[0] = item1;

int len = lookup_reply__get_packed_size(nlr);

But that's kind of overkill in a way, it's shorter just to write:
LookupReply nlr = LOOKUP_REPLY__INIT;
Item item1 = ITEM__INIT;
Item *items[1] = { &item };

nlr.n_replica_list = 1;
nlr.replica_list = items;
item1.id = 1;
int len = lookup_reply__get_packed_size(&nlr);
Furthermore, using the latter approach, you can avoid malloc(), and
therefore (most of) the possibility of memory leaks.

daveb

unread,
Nov 27, 2008, 10:48:14 PM11/27/08
to Protocol Buffers
I should mention too: I plan to eventually add a generated function
"item__init(Item *)" to initialize a message. i plan to add this when
i fix default values for non-fundamental types (which are currently
ignored).

(i haven't had a huge amount of time to deal with these few niggling
issues, but i've now got the design in my head, and the coding should
be pretty easy)

- dave

daveb

unread,
Nov 30, 2008, 9:50:12 PM11/30/08
to Protocol Buffers
BTW: I just released protobuf-c 0.6 which include the item__init()
function (and it also supports default-values properly now).

- dave

osis...@gmail.com

unread,
Dec 3, 2008, 5:23:19 AM12/3/08
to Protocol Buffers
Thank you very much Dave for your quick and detailed replies
I'll try that out soon.

Aviad
> > > >Aviad-הסתר טקסט מצוטט-
>
> -הראה טקסט מצוטט-
Reply all
Reply to author
Forward
0 new messages