Reputation: 247
Im starting to use ei library to encode in my c program and then pass that encoded data to my erlang client. I know I can use binary_to_term/1 to get the data in erlang.
I am having a hard time trying to encode that data before sending to over the socket. BTW, I have a connection established.
int index = 0;
const char *buff = "Stackoverflow";
char p[strlen(buff) + 1];
ei_encode_string_len(p, &index, buff, strlen(buff))
Input is buff, the third parameter. p is the output buffer I want the encoded string to be.
But the data is not being encoded and put in the output buffer
I tried to print the output buffer by traversing each charecter and could see that 107 is printing which in, ETF, means string but not sure why the whole string is not being encoded.
Is there something I am missing ?
Thank you!
Appreciate your help!
Upvotes: 3
Views: 164
Reputation: 20014
Your code is fine, except the buffer you're using to encode into is too small.
First, let's look at the binary obtained by converting the term "Stackoverflow"
using term_to_binary
:
1> Term = term_to_binary("Stackoverflow").
<<131,107,0,13,83,116,97,99,107,111,118,101,114,102,108,
111,119>>
The first byte, 131, is the version magic number of the term; let's ignore it for now. The second byte, 107, indicates the type of the encoded data, as you already explain in your question.
Next, let's use the following code, similar to yours, to look at the data created by ei_encode_string_len
:
int index = 0;
const char *buff = "Stackoverflow";
char p[strlen(buff) + 3];
memset(p, 0, sizeof p);
ei_encode_string_len(p, &index, buff, strlen(buff));
for (int i = 0; i < sizeof p; ++i)
printf("%d ", (unsigned char)p[i]);
printf("\n");
Compiling and running this results in the following output:
107 0 13 83 116 97 99 107 111 118 101 114 102 108 111 119
One thing to note is that in this code, the buffer p
is larger than in your code by two extra bytes. This is because the second and third byte of the encoded buffer—here holding the values 0
and 13
respectively—are a two-byte big-endian value encoding the string length, 13 bytes. We can see this length easily in Erlang:
2> length("Stackoverflow").
13
Following those two bytes are the string data, the values of which we can also see using Erlang:
3> [C || C <- "Stackoverflow"].
[83,116,97,99,107,111,118,101,114,102,108,111,119]
The values ei_encode_string_len
produces match exactly, and these are also the same as what we see in the binary produced by term_to_binary
.
Finally, back to the version magic number: it must be the first byte in any encoded term. To get it into your buffer, use ei_encode_version
prior to encoding any actual data:
int index = 0;
const char *buff = "Stackoverflow";
char p[strlen(buff) + 4];
memset(p, 0, sizeof p);
ei_encode_version(p, &index);
ei_encode_string_len(p, &index, buff, strlen(buff));
for (int i = 0; i < sizeof p; ++i)
printf("%d ", (unsigned char)p[i]);
printf("\n");
Note that we've increased the size of p
by 1 byte to hold the version magic number. Compiling and running this code produces the following value, which exactly matches the value term_to_binary
gives us:
131 107 0 13 83 116 97 99 107 111 118 101 114 102 108 111 119
Note that you can avoid these buffer sizing problems by using the ei_x_...
function variants for encoding, since they use a dynamic buffer that's resized as needed.
Upvotes: 4