C++ reference byte array - c++

I have an issue with C++ and creating a reference byte[].
In C# my method is:
public static void SetBitAt(ref byte[] Buffer, int Pos, int Bit, bool Value)
{
byte[] Mask = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
if (Bit < 0) Bit = 0;
if (Bit > 7) Bit = 7;
if (Value)
Buffer[Pos] = (byte)(Buffer[Pos] | Mask[Bit]);
else
Buffer[Pos] = (byte)(Buffer[Pos] & ~Mask[Bit]);
}
I want to translate it to C++, but I can't get the refworking for C++. I saw something about the & symbol and I tried something like this:
void SetBitAt(byte& buffer[], int Pos, int Bit, bool Value)
{
byte Mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
if (Bit < 0) Bit = 0;
if (Bit > 7) Bit = 7;
if (Value)
{
buffer[Pos] = (byte)(buffer[Pos] | Mask[Bit]);
}
else
{
buffer[Pos] = (byte)(buffer[Pos] & ~Mask[Bit]);
}
}
but then I get the Error:
'buffer': arrays of references are illegal.
So how can I change my C++ code to work with a reference array?
EDIT:
I use this method for setting a buffer, but it doesn't change when I use this method.
other class:
buffer = ReadDB(2); //Read the values in the DataBlock
SetBitAt(buffer, 0,0 true); //Set bit 0,0 to 1(true)
WriteDB(2, buffer); //Write the values to the Datablock
but the buffer doesn't change. its the same value.

If you want to pass array by reference, you should
void SetBitAt(byte (buffer&)[10], int Pos, int Bit, bool Value)
But in your case, you don't need that, just
void SetBitAt(byte buffer[], int Pos, int Bit, bool Value)
Note in this case array will decay to pointer (i.e. byte*), that means the size of array won't be reserved as pass by reference would.

'buffer': arrays of references are illegal.
This is due to operator precedence. Saying byte &buffer[] is an array of references, while saying byte (&buffer)[size] is a reference to an array.
See C++ pass an array by reference for more details.
So how can I change my C++ code to work with a reference array?
When passing your array as a function argument, you should drop & symbol. You can still modify the contents of your array because the array's address is passed instead.
Assuming you have a typedef of char to byte, your function signature should look like this:
void SetBitAt(byte buffer[], int Pos, int Bit, bool Value) { ... }
Note that the above is equivalent to passing a pointer:
void SetBitAt(byte *buffer, int Pos, int Bit, bool Value) { ... }
Modifying the contents of your array is still a matter of saying buffer[Pos] = // some value;
This post on What is array decaying? should be useful.

Shouldn't it simply be like this:
void SetBitAt(byte buffer[], int Pos, int Bit, bool Value)
{
byte Mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
if (Bit < 0) Bit = 0;
if (Bit > 7) Bit = 7;
if (Value)
{
buffer[Pos] = (byte)(buffer[Pos] | Mask[Bit]);
}
else
{
buffer[Pos] = (byte)(buffer[Pos] & ~Mask[Bit]);
}
}
In this way, buffer is passed as a pointer, and buffer[Pos] references to the Pos-th element of buffer. It is plain C, but it should work.

You can pass it simply by address as:
void SetBitAt(byte* buffer, int Pos, int Bit, bool Value) { ... }
or simply as:
void SetBitAt(byte buffer[], int Pos, int Bit, bool Value) { ... }
Either one will tell the compiler that byte pointer is passed to function, althrough with second header you omit pointer arithmetics ;)

Related

Arduino combine several arrays (c++)

I want to know how can I combine several byte arrays into 1?
I have this:
byte MessageStart [] = {0x02};
byte Next [] = {0x5C , 0x73};
byte messgae[] = {0x30 , 0x35};
byte BeforeEnd [] = {0x5C , 0x3B};
byte MessageEnd [] = {0x03};
I want to have one byte array with all of them, the final result needs to be:
byte Final [] = {0x02, 0x5C, 0x73, 0x30, 0x35, 0x5C, 0x3B, 0x03}
How do I do this?
Maybe something like this:
byte *concatbytes(const byte *source, byte *destination, int length)
{
for (int i = 0; i < length; i++)
{
*destination++ = *source++;
}
return destination;
}
...
byte MessageStart[] = { 0x02 };
byte Next[] = { 0x5C , 0x73 };
byte messgae[] = { 0x30 , 0x35 };
byte BeforeEnd[] = { 0x5C , 0x3B };
byte MessageEnd[] = { 0x03 };
byte Final[8]; // 8 is the hardcoded length of sum of all 5 arrays
byte *dest = Final;
dest = concatbytes(dest, MessageStart, sizeof(MessageStart));
dest = concatbytes(dest, Next, sizeof(Next));
dest = concatbytes(dest, messgae, sizeof(messgae));
dest = concatbytes(dest, BeforeEnd, sizeof(BeforeEnd));
dest = concatbytes(dest, MessageEnd, sizeof(Next));
The Final array may be obtained differently, for example by dynamic memory allocation. This is left as an exercise for the reader.

Generating a static ranged integer value based on an array of bytes

Okay, this is a strange one I believe, and I have absolutely no idea of how to go about it.
So basically what I'm looking for is a way to generate a fixed ranged integer value based on a given array of bytes.
Say I have an array named imALonleyArray
unsigned char imALonleyArray[16] = {0x33, 0x7E, 0xD5, 0x8F, 0xC3, 0x01, 0x39, 0x0C, 0x5B, 0x0F, 0x80, 0x9C, 0x78, 0x90, 0x89, 0xF5};
I'd like to somehow generate a static ranged integer value based on the above array.
Why you might ask?
I need to assign a fixed int value from possibly int_min to int_max or, really for this program (0-1487) based on a given users 16 byte session token.
Example:
int getIntRangeFromGivenBytes(unsigned char *arr, int minValue, int maxValue){
/*Magic here that somehow computes then returns an int value between
minValue and maxValue based on the given bytes provided by the 'arr' argument*/
}
I tried my best to describe what I'm trying to do here. I'm a newb here, please don't shoot me down.
Thanks in advance!
From what I understand, you're asking for an algorithm that for a given char array, generate an integer within a given range [a,b], where the same integer will pop up for the same input.
A really easy and simple one would be to add them all together and use % modulo to get it into the range.
int interval = maxValue - minValue;
int increment = 0;
for(int i = 0; i < array_size; ++i){
increment += array[i];
increment = increment % interval; // this ensures output is always within the interval
}
int final_answer = increment + a;
If you want one that's reversible, that'd be different. And frankly impossible if there's more possible arrangements of the array than there are elements in the interval. (If two different arrays map to the same integer, how do you reverse it?)
An example, let's say you have interval [0,5].
unsigned char array[2] = {0x00, 0x00}; // assign to 0
unsigned char array[2] = {0x00, 0x01}; // assign to 1
unsigned char array[2] = {0x00, 0x02}; // assign to 2
unsigned char array[2] = {0x00, 0x03}; // assign to 3
unsigned char array[2] = {0x00, 0x04}; // assign to 4
unsigned char array[2] = {0x00, 0x05}; // assign to 5
unsigned char array[2] = {0x00, 0x06}; // now what?
So you need to make sure that the interval is large enough, or limit the size of the char array enough that there's no collisions.
sidenote: the word static means something very specific in C++, so your question was a bit confusing.
You want a hash, and a simple hash on values that are numeric integer types to some range is division:
uint64_t to_value(const uint8_t *array) {
uint64_t result = array[0];
for (int i = 1; i < 8; ++i)
result = (result << 8) | array[i];
return result;
}
uint64_t to_range(uint64_t input, uint64_t lower, uint64_t upper) {
if (lower > upper)
std::swap(upper, lower);
if (upper == std::numeric_limits<uint64_t>::max() &&
lower == std::numeric_limits<uint64_t>::min())
return input;
auto range = upper - lower + 1;
return lower + ((input - lower) / range);
}
Use:
uint64_t my_hash(const uint8_t *data) {
auto value = to_value(data);
return to_range(value, 0, 1487);
}
Whether such a hash has some other properties that you haven’t listed is another story. But it fulfills the requirements you state.

data segment too large while compiling

Here, I am passing an array of bits to some other function.
Since, array size is too large, it throws an error saying "data segment too large" while compiling.
I have newly edited the code. But, the error: data segment too large still exists
This is the code:
char TxBits[]={0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,1,0,1,0,1,1,0,1,1,0,1,1,1,0,
0,0,0,1,1,0,0,0,1,0,0,1,0,0,1,1,1,1,1,1,0,1,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int nTxBits = sizeof(TxBits)/sizeof(char);
void data(char *TxBits,int nTxBits, int loopcount)
{
int i;
for (i = 0;i < nTxBits;i++)
{
gpio=TxBits[i];
wait(loopcount);
}
}
So, I am thinking of converting bits in an array to bytes and passing to function. May I know how to proceed? open to suggestions.
Kindly reply
From your code I reckon you're working with some micro-controller so I'm not sure if you're serious about the C++ tag or not. If you are, this is a C++-style solution which uses std::bitset (specialised container for dealing with bits which will require less space):
std::bitset<134> foo (std::string("01010101010101010101010100101010101010101010101010010101010101010101010101001010101010101010101010100101010101010101010101010100000000"));
void data(const std::bitset& bitset, int loopcount) {
// if C++11
for (auto& bit : foo) {
gpio = bit;
wait(loopcount);
}
// if C++98
// for (int i = 0; i<bitset.size(); i++) {
// gpio = foo[i];
// wait(loopcount);
// }
}
You probably need this:
void data(char *TxBits, int size) // size of the number of elements of your table
{
int i;
for (i = 0;i < size; i++)
{
gpio=TxBits[i];
wait(loopcount);
}
}
Calling the function
data(TxBits, sizeof(TxBits) / sizeof(TxBits[0]);
To get the number of elements of an array we use sizeof(TxBits) / sizeof(TxBits[0] where sizeof(TxBits) is the number of bytes the array takes in memory and sizeof(TxBits[0] is the size of one element of the array.
I am passing an array of bits to some other function
No, you are passing an array of bytes, each byte having the binary value 00000000 or 00000001.
In order to save memory, you should store bit values as actual bits and not as bytes:
uint8_t TxBits[]=
{ 0x55, // 0,1,0,1,0,1,0,1,
0x55, // 0,1,0,1,0,1,0,1,
0x55, // 0,1,0,1,0,1,0,1,
0x00, // 0,0,0,0,0,0,0,0,
0x20, // 0,0,1,0,0,0,0,0,
...
};
size_t nTxBits = sizeof(TxBits) / 8;
You should also avoid the char type whenever doing arithmetic, since it has implementation-defined signedness.
Also if this is a small microcontroller system, you should allocate the data in ROM instead of RAM whenever possible. That is: const uint8_t TxBits[].
Your Parameter is not declared correctly. Replace this:
void data(char TxBits)
by this
void data(char [] TxBits)
Your function
void data(char TxBits)
Should be
void data(char *TxBits, size_t nTxBits)
{
int i;
for (i = 0;i < nTxBits;i++)
{
gpio=TxBits[i];
wait(loopcount);
}
}
You can call it by:
data ( TxBits, sizeof(TxBits)/sizeof(TxBits[0]) );
In this specific case, you have a char array, and you can also write:
data (TxBits, sizeof(TxBits));

How to change the code using lambda expression?

I'm study about c++ using lambda expression.
I'm just tried change the code that already coded using for or while, then i have the question about lambda.
I'm just change the code using lambda or for_each (c++11). How to change?
Here is a code that want to change.
std::string PointToString(void* p_pData)
{
char* p = (char*)p_pData;
int iLength = 0;
std::memcpy(&iLength, p, sizeof(int));
p += sizeof(int);
std::string sRet;
std::array<char, 3> szB;
sRet.append("0x");
for ( int i = 0; i < iLength; i++ )
{
sprintf(szB.data(), "%02X", (unsigned char)*(p++));
sRet.append(szB.data());
}
return sRet;
}
This code just convert a memory value to hex code.
That function called like this.
char szB[15] = {0x0b, 0x00, 0x00, 0x00, 0xc7, 0xd1, 0xb1, 0xdb, 0xc0, 0xd4, 0xb4, 0xcf, 0xb4, 0xd9, 0x2e};
void* p = nullptr;
p = (void*)szB;
sRet = PointToString(p);
The Result may be 0x0B000000C7D1.....
I want to try lambda in PointToString function. How can I change that function?
Well, you could write:
std::for_each(p, p + iLength, [&](unsigned char ch)
{
sprintf(szB.data(), "%02X", ch);
sRet.append(szB.data());
});
The & means that you will operate on szB and sRet by reference, instead of operating on copies of them.
IMHO it's not a significant improvement over your original code though.

How to declare an array of pointers to multidimensional arrays

// LED definitions for each step
static uint8_t route1Step0LedsOn[] = { 0x30, 0xff };
static uint8_t route1Step0LedsOff[] = { 0x26, 0xff };
static uint8_t route1Step1LedsOn[] = { 0x18, 0x45, 0x21, 0xff };
static uint8_t route1Step2LedsOn[] = { 0x56, 0x33, 0x42, 0x31, 0xff };
// First route (consisting of 3 steps + terminator).
static uint8_t* routeLeds1[][2] =
{
{ route1Step0LedsOff, route1Step0LedsOn },
{ NULL, route1Step0LedsOn },
{ NULL, route1Step0LedsOn },
{ NULL, NULL }
};
// Second route.
static uint8_t* routeLeds2[][2] =
{
// LED elements not shown, but similar to route 1.
{ NULL, NULL }
};
// Array of routes.
static ??? routes[] =
{
NULL,
routeLeds1,
routeLeds2,
NULL
};
I'm not sure of the correct type for routes[].
I'd like to know what the ??? should be?
I'm using a micro controller and MUST use arrays in order to force the arrays into flash memory instead of RAM.
You can't convert arrays to "pointers to pointers... to pointers" because they're dereferenced differently; trying to use a multidimensional array as a "pointer to... pointer" to something will cause undefined behaviour the same way dereferencing an invalid pointer would.
In memory, a "pointer to a pointer..." to an object is represented by
a -> b -> c -> ... -> object
Where a, b, c, ..., and object are in completely different parts of memory. To index a pointer, the pointer is dereferenced.
Arrays, however, are stored in a contiguous memory. For instance, int a[2][2] would be
[0,0][0,1][1,0][1,1]
Indexing a multidimensional array does not dereference a pointer, it changes the arithmetic that is used to calculate the offset from the beginning of the array that the desired value is at. The formula would be
address of array + index1 * sizeof(first dimension) + index2 * sizeof(second dimension) + ... + indexn * sizeof(object)
Where sizeof(nth dimension) is the size of all the subdimensions put together. For instance with int a[3][2] which is represented by
[0,0][0,1][1,0][1,1][2,0][2,1]
, the index a[2][1] would be
address of a + 2 * (sizeof(int) * 2) + 1 * sizeof(int)
Which, in C++, would be (char*)a + 16 + 4, the last element of the array.
To solve this problem, you need to use pointers only. You should not (and cannot) be storing multidimensional arrays alongside pointers in the same array.
I'm having a hard time putting this all into words; if I'm not making sense, please say so.
Try this:
typedef uint8* Array1; // first column/row
typedef Array1 Array2[2]; // uint* name[2]
typedef Array2* Array3; // get the idea?
// Array of routes.
static Array3 routes[] =
{
NULL,
routeLeds1,
routeLeds2,
NULL
};
Your problem is the multidimensional array:
If you need to go the array route, you can just add an extra step:
static uint8_t route1Step0LedsOn[] = { 0x30, 0xff };
static uint8_t* route1Step0[] = { NULL, route1Step0LedsOn };
static uint8_t** routeLeds1[] = { route1Step0 };
static uint8_t*** routes[] =
{
NULL,
routeLeds1,
NULL
};
If some of the arrays are fixed lengths, it may be possible to clean some of this up a little.
But IMO this is getting pretty ugly and could do with some real structs, rather than raw arrays.
If you're not tied to ussing arrays for some technical reason, you could change to use a structure like this: (Note if you're using C++11, then the constructors and construction can be made a lot nicer). You'll also need a make_vector helper, of which there are several floating around, if you want a nicer construction.
struct LedList
{
LedList( const std::vector<uint8_t> & v ) : leds( v ) {}
std::vector<uint8_t> leds;
};
struct LedStep
{
LedStep( const & LedList on_, const & LedList off_ ) : on_leds(on_), off_leds(off_) {}
RouteStepLedList on_leds;
RouteStepLedList off_leds;
};
struct LedRoute
{
LedRoute( const std::vector<LedStep> & steps_ ) : steps(steps_) {}
std::vector<LedStep> steps;
};
struct Route
{
Route( const std::vector<LedRoute> & routes_ ) : routes(routes_) {}
std::vector<LedRoute> routes;
};
//All routes
Route r( make_vector<LedRoute>()(
//First route
make_vector<LedStep>()(
//First step of first route
LedStep(
make_vector<uint8_t>()( 0x30 ),
make_vector<uint8_t>()( 0x26 )
) )(
//Second step of first route
LedStep(
make_vector<uint8_t>(),
make_vector<uint8_t>()( 0x18 )( 0x45 )( 0x21 )
) )(
//Third step of first route
LedStep(
make_vector<uint8_t>(),
make_vector<uint8_t>()( 0x56 )( 0x33 )( 0x42 )( 0x31 )
) ) ),
//Second route.
make_vector<LedStep>()(
//First step of second route
LedStep(
...
) ) (
//Second step of second route
...
);