FlattenVAR a struct with a string in it

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

FlattenVAR a struct with a string in it

Post by mcsummation »

I have a struct with a string in it. When I FlattenVar it, the length of the resultant string is correct. However, when I UnflattenVar that into another instance of the struct, it is messed up. (I am trying to implement John's suggestion of sending a lot of data back from a slave, all at once. One piece of data is a string, which I simply stuck in the struct with the rest of the stuff.) I generated this little test case that doesn't have any Bluetooth stuff in it and it still fails.

Code: Select all

struct abc {
    long lAA;
    float fAA;
    string sAA;
};
abc def, ghi;
string sFlat;

task main()
{
ClearScreen();
def.lAA = 2;
def.fAA = 2.5;
def.sAA = "a string";
sFlat = FlattenVar(def);
UnflattenVar(sFlat, ghi);
NumOut(0, LCD_LINE7, def.lAA);
NumOut(15, LCD_LINE7, def.fAA);
TextOut(35, LCD_LINE7, def.sAA);
NumOut(0, LCD_LINE8, ghi.lAA);
NumOut(15, LCD_LINE8, ghi.fAA);
TextOut(35, LCD_LINE8, ghi.sAA);
Wait(10000);
}
Without the string in the struct, it works properly.

I await enlightening.
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: FlattenVAR a struct with a string in it

Post by afanofosc »

unflattening really only works (well) with fixed length things. You can use a string (aka an array of bytes) so long as it is always N bytes long. flattening works regardless. But you need to tell unflatten what the structure looks like, including exactly how many elements are in any arrays in the struct. So it is not ideal in the case where you have a struct containing what really is a variable length element.

My advice? Rarely, if ever, pass a string between two NXTs - especially if you are using flattened structures for the message body. Figure out a better way. Can you give me an example of a case where you really need to pass a string from one NXT to another? I suppose if you were implementing a "TextOut" command and wanted to pass the string across to the other NXT. But unless the string is read from a file or entered by a user somehow (i.e., it is not a string hard-coded in your program) then pass a byte instead that can be used to look up the string from an array of strings on the receiving end.

The unflatten operation will work if you give it an example structure with the right number of elements in the string member.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: FlattenVAR a struct with a string in it

Post by afanofosc »

Specifically, if you ArrayInit(ghi.sAA, 0, 9); it will work since the sizeof ghi will match the number of bytes in the flattened buffer.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

Re: FlattenVAR a struct with a string in it

Post by mcsummation »

I think you should add to the F1 documentation for struct AND FlattenVar, "Don't put a string in the struct. It won't flatten properly."
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: FlattenVAR a struct with a string in it

Post by afanofosc »

It does flatten properly. It also unflattens properly. You just need to give unflatten the right pattern to use when it unflattens the buffer, as I explained. When you put arrays in structures you just make it harder on yourself to always initialize the structure to the correct size before you call unflatten.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
spillerrec
Posts: 358
Joined: 01 Oct 2010, 06:37
Location: Denmark
Contact:

Re: FlattenVAR a struct with a string in it

Post by spillerrec »

I have been wondering about this before, why doesn't flatten add a word in front of the array data telling it how long the array is? It could really simplify many reading/storing tasks, instead of reading a byte/word, initialize the array and then use unflatten (and the other way around when storing).
My blog: http://spillerrec.dk/category/lego/
RICcreator, an alternative to nxtRICeditV2: http://riccreator.sourceforge.net/
mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

Re: FlattenVAR a struct with a string in it

Post by mcsummation »

afanofosc wrote:It does flatten properly. It also unflattens properly. You just need to give unflatten the right pattern to use when it unflattens the buffer, as I explained. When you put arrays in structures you just make it harder on yourself to always initialize the structure to the correct size before you call unflatten.
The whole reason for using "string" instead of "byte array" is so I don't have to worry about the underlying implementation. Are characters 8 bits or 16 bits. I don't know and don't care - "string" takes care of that for me. I hated standard "C" null terminated array of characters because you could NEVER have a 0 imbedded in it. The way you've done strings (with a length attribute stored somewhere - again, I don't care where) is much better. I don't want to have to worry about what a string looks like on the inside. Either make strings work properly for flatten/unflatten or put "don't do this" in the F1 help panel.
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: FlattenVAR a struct with a string in it

Post by afanofosc »

A string in NXT-land is just a byte array that has an extra element added to the end which is always 0. That is all that the string type is in NXC. The arrtostr and strtoarr opcodes in the NXT VM simply append a null to the end of the array (arrtostr) or remove the last element (strtoarr) whether it is a null or not. When you define a structure that contains a string you are saying to the VM, look at me I am creating a type where every instance of this type will have a completely different length so you won't know how to deal with it unless I help you. The NXT VM stores the length of every array in the dope vector array. Astring is not a native type in the NXT VM. It's just another byte array that happens to always be one byte longer than an equivalent array that is not intended for use with the opcodes that are intended for null terminated byte arrays (aka strings).

There's nothing broken about flatten or unflatten that needs a warning. The size and the organization of the members of the structure that you pass into unflatten tells the unflatten opcode where to put the bytes in the buffer into the output argument. If you pass in a struct instance that contains an empty string then how would it know that it should put 9 bytes into that empty string?

Are you going to give me an example of a reason to stick a string in a structure that needs to be flattened and unflattened?

I could, I suppose, add a pair of EX versions of the flatten and unflatten opcodes which for all array types that are flattened would include a word-sized length at the start of the flattened buffer that could be used when unflattening the array type.

Here is how unflatten is documented to behave:

http://bricxcc.sourceforge.net/nbc/doc/ ... atten.html

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
mcsummation
Posts: 220
Joined: 23 Jan 2012, 17:07
Location: Round Rock, TX

Re: FlattenVAR a struct with a string in it

Post by mcsummation »

a) That's NBC documentation, not NXC.
b) It does not tell me I can't put a string in there.

I'm done arguing about this. It's broke, you won't admit it, but I'll bet other people fall in the same pothole. In fact, it looks like someone had already fallen into it before I came along.
afanofosc
Site Admin
Posts: 1256
Joined: 26 Sep 2010, 19:36
Location: Nashville, TN
Contact:

Re: FlattenVAR a struct with a string in it

Post by afanofosc »

It is definitely not broken because it works fine if you do it like I told you to do it. That it doesn't work the way you think it ought to work does not mean it is broken. It works exactly like it is designed to work. Don't put variable length data in a struct if you want to use flatten/unflatten without knowing on the receiving end the length of the variable length data in the struct.

Now, like I asked before, please show me a case where you need to send a string in a message between two NXTs.

John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests