How exactly does strcat manage memory in NXC? I'm writing a program to receive packets of data over Bluetooth from a computer, and I'm simply concatenating each new packet that comes in to a single string. The problem is that the program crashes after the string's length exceeds a little over 6000. I saw somewhere else on Mindboards that an NXC program has 32kB of memory available during execution, so I came to the conclusion that strcat must be the source of the problem since the string is not large enough to be using up that amount of memory. So what is the best way to combine the packets of data so that the program does not exceed its memory limitations?
As shown in muntoos post, you have to be very careful when you are dealing with large strings/arrays because it ends up making temporary variables.
To make matters worse, in NBC there is no such thing as scope, all variables are global/static so even when it goes out of scope in NXC it does not get cleared. And it is "impossible" to clear them, since you don't have access to them. (Well, there is a dirty trick, run the function again but with an empty array, depending on the function you might be able to clear most of them.)
Re: Memory management of NXC strcat
Posted: 18 Jun 2011, 23:03
by h-g-t
I wonder, would writing the input to a file whilst it is coming in be too slow?
Re: Memory management of NXC strcat
Posted: 20 Jun 2011, 21:48
by afanofosc
I would recommend using a simple NBC asm block that uses the strcat opcode to concatenate the new input string to your buffer. You will need one temporary byte array to hold the output of strcat and then copy that into your original buffer. After that you can empty the temporary with arrinit.
John Hansen
Re: Memory management of NXC strcat
Posted: 20 Jun 2011, 22:26
by muntoo
afanofosc wrote:I would recommend using a simple NBC asm block that uses the strcat opcode to concatenate the new input string to your buffer. You will need one temporary byte array to hold the output of strcat and then copy that into your original buffer. After that you can empty the temporary with arrinit.
task main()
{
string large_buffer, tmp;
string new_data;
// read data from bluetooth
//append it to large_buffer
asm {
strcat tmp, large_buffer, new_data
mov large_buffer, tmp
arrinit tmp, 0, 0
}
}
So he has to have a third buffer to store the results of adding new_data to the end of large_buffer and then he needs to copy that back into a larger version of large_buffer. You can't use large_buffer as both an input and an output in strcat or you will overwrite your source before you copy it to your destination. The problem with strcat is that it is an inline function that takes 2 string input arguments and returns a string so you have the 2 variables you pass in, the 2 local variables that get a copy of your inputs, and the local return value variable and then a string buffer temporary that holds the return value of all string functions before the value is assigned to the LHS of the string expression. If I had a better optimizer these temporaries/locals would all be removed. If I were really clever and ambitious I could add compiler code that empties out any local arrays/strings when they go out of scope or are "released" by the compiler.
John Hansen
Re: Memory management of NXC strcat
Posted: 20 Jun 2011, 23:23
by muntoo
afanofosc wrote:You can't use large_buffer as both an input and an output in strcat or you will overwrite your source before you copy it to your destination.
OT: Say, have you read the 'Dragon Book'? Apparently, it's the must read book for compiler writers. (It's on my to-read list.)
Re: Memory management of NXC strcat
Posted: 21 Jun 2011, 16:07
by afanofosc
arrbuild is the same as strcat except that one is designed to work with null terminated byte arrays (strcat) while the other is designed to work with any old kind of array. They both have the same limitation that you can't use any of the inputs as the output or it will be overwritten (actually reallocated to a different memory location) before you copy the input to the output.
John Hansen
Re: Memory management of NXC strcat
Posted: 23 Jun 2011, 02:26
by ejvaughan
afanofosc wrote:In the OP's case he has something like this:
task main()
{
string large_buffer, tmp;
string new_data;
// read data from bluetooth
//append it to large_buffer
asm {
strcat tmp, large_buffer, new_data
mov large_buffer, tmp
arrinit tmp, 0, 0
}
}
So he has to have a third buffer to store the results of adding new_data to the end of large_buffer and then he needs to copy that back into a larger version of large_buffer. You can't use large_buffer as both an input and an output in strcat or you will overwrite your source before you copy it to your destination. The problem with strcat is that it is an inline function that takes 2 string input arguments and returns a string so you have the 2 variables you pass in, the 2 local variables that get a copy of your inputs, and the local return value variable and then a string buffer temporary that holds the return value of all string functions before the value is assigned to the LHS of the string expression. If I had a better optimizer these temporaries/locals would all be removed. If I were really clever and ambitious I could add compiler code that empties out any local arrays/strings when they go out of scope or are "released" by the compiler.
John Hansen
Hmm. I tried your code and it ends up freezing my NXT. I have no clue why. Here is my code: