How can i pass a byte array as an argument to lua script method from C++ code?
Are only int, float or string data types allowed?
Also how can i retrive byte array from lua script method?
I will pass a raw byte array to script. It will parse and use it.
Thanx.
Depends what you want to do. Lua strings are immutable byte arrays, so if they're small you're probably best off simply turning the byte array into a string with lua_pushlstring and passing it in like that --- yes, embedded \0 is supported and works fine. But because they're immutable Lua will end up copying the string every time you want to modify it, so it may not be suitable for your requirements.
Other options are:
copy the data back and forth between your C++ byte array and a Lua array (that is, table of numbers). This will be fairly expensive in memory, but is probably the easiest way.
wrap you C++ byte array in a lightuserdata and provide Lua bindings to let you access it directly. This is the most efficient, but is quite a lot of code.
Int and float values will be converted to Lua's number type (by default, double).
If the script itself just needs to keep a pointer to pass between functions, blobs of C data are usually pushed as light userdata:
lua_pushlightuserdata(L, bufptr);
When passing arrays of bytes to Lua, strings are normally used (strings of arbitrary data can be created using lua_pushlstring):
lua_pushlstring (L, bufptr, buflen);
This will create an immutable string in Lua, which can only be modified by creating new strings.
If you need to work with mutable byte buffers in Lua (not recommended- low-level byte manipulation is what C was designed for and Lua was not), the best bet is to create a userdata type for the buffer with methods to get and set tailored to the use case (individual positions as numbers, ranges as strings or tables of numbers).
Related
In C++, is it possible to create a std::array of char (or a std::vector) from a char pointer without copying data?
I know I can write something like that but data are copied into the array, which is not optimized:
#define BUFFER_SIZE 256
...
char *buffer;
std::array<char, BUFFER_SIZE> data(buffer, buffer + BUFFER_SIZE);
I would like a solution to pass data by pointer, without copying data.
No not really. Arrays and vectors own their data. Strings are the same.
I would like a solution to pass data by pointer, without copying data.
Well You can always pass by reference but of course if you change it in a routine .... well ...... it changes it.
For characters you can use a COW string (Moooooo!) or Copy On Write string. The idea here is that a copy of the string data itself is only made if you actually try to change the string. So it's kind of the best of both worlds. Unfortunately (or fortunately depending on your point of view) the standard library string isn't one. If I remember correctly some older STL strings used to be implemented like that. You can of course write your own in short order if you are reasonably C++ proficient, or you can likely find an implementation floating around somewhere. I have one I've used for like 30 years which works well enough for my purposes.
A C function API accepts uint8_t* and size_t as parameters:
bool foo(uint8_t* buff, size_t bufflen)
What is the best way to manage and handle in C++ layer invoking this API. Is string, vector or list a better option
Just make sure while calling this API from C++ you always pass a uint8_t type pointer . normal array uint8_t arr[x] (x is any +ve number) will also work. Just make sure address you passed has data of type uint8_t with correct size of the buffer.
e.g. uint8_t arr[6]; for this the call will be foo(arr,6);
You probably want std::vector<uint8_t> while passing data() and size().
You can't pass a container to the C function. You can still use one in your C++ code, but you'll need to pass a pointer to the data, in accordance to what the C function parameters are. Use a vector. This is equivalent to an array in C, in that the data is stored contiguously in memory.
std::vector<uint8_t> myData;
// ... fill myData
// for c++11 and later,
foo(myData.data(), myData.size());
// pre-c++11
foo(&(myData[0]), myData.size());
Is string, vector or list a better option?
Well, list is a non-starter, because it will not store the sequence in contiguous memory. In other words, the C code would not be able to take a pointer to the first element and increment it to get to the second element.
As for the other two, that depends on the rest of your C++ code. I would lean towards vector rather than string, but you haven't really provided enough context for that to be any more than a general feeling.
Usually I would go with a helper class that has an method that either takes a vector, or a custom structure that acts like a span - i.e. a pair<void*,int>, or perhaps even a span (but I'm not allowed the C++14 crayons).
If the data really is character-based the std::string and string spans can work well, but if it is really binary data, vector and vector spans are the better encapsulation, IMBO.
I still don't want to call that directly from application code if what is actually in there is structured data. You can easily write a method that takes an expected structure type and generates the pointer and sizeof(instance).
You can write a generic template that would accept any structure and convert it to a void*/char* and length, but that tends to open your code up to more accidents.
I came across a few articles referring to a C++ blob. What this is?
I have seen some code that uses it like this:
char blob[100];
element = lst->putBlob(blob, strlen(blob));
The code is not really important here, I just want to know what a "blob" is.
"Blob" stands for Binary large object.
A "blob" is a common acronym for "Binary Large Object", which means it's an object holding a large amount of binary data. Some languages has native blob types, but C++ doesn't. Never the less, creating a blob is simple enough - you just create an array of bytes. In your example, this is done by creating an array of chars. This might be confusing, though, as an array of chars has a special meaning in C++ - it's also a string. Still, if used as a blob, it can hold any kind of data (in which case strlen won't work).
The constraint is that it should be contiguous memory. The reason is, this is being sent to another language legacy code, which expects it in that format as a 2D array.
so esentially i want to send
char *temp[20] = { "abc", "def"};
etc where abc, def are part of a space thats 20 byte length.
Now, i would like to dynamically create this array and add as many 20 character or less strings to it.
And then send that as an array into the different layer.
Whats the best way to do this.
std::vector< std::array<char, 20> > will do the trick
vector allows dynamically allocating more memory for more strings, the type std::array<char,20> ensures that each member of the vector is indeed 20 characters (make sure to verify boundaries on copy etc, as with any array).
This is for newer C++ standard, IIRC, so older compilers might not support it. Use boost.array instead, then.
Now I have a database, which one field type is an array of byte.
Now I have a piece of memory, or an object. How to convert this piece of memory or even an object to a byte array and so that I can store the byte array to the database.
Suppose the object is
Foo foo
The memory is
buf (actually, don't know how to declare it yet)
The database field is
byte data[256]
Only hex value like x'1' can be insert into the field.
Thanks so much!
There are two methods.
One is simple but has serious limitations. You can write the memory image of the Foo object. The drawback is that if you ever change the compiler or the structure of Foo then all your data may no longer loadable (because the image no longer matches the object). To do this simply use
&Foo
as the byte array.
The other method is called 'serialization'. It can be used if the object changes
but adds a lot of space to encode the information. If you only have 256 bytes then you
need to be watchful serialization doesn't create a string too large to save.
Boost has a serialization library you may want to look at, though you'll need to careful about the size of the objects created. If you're only doing this with a small set of classes, you may want to write the marshalling and unmarshalling functions yourself.
From the documentation:
"Here, we use the term "serialization" to mean the reversible deconstruction of an arbitrary set of C++ data structures to a sequence of bytes. "