Consider the follow variables:
std::uint8_t value;
const bool bits[8] = { true, false, false, true,
false, false, true, false };
If I was to print out the array of bools to the console
for (int i = 0; i < 7; i++ )
std::cout << bits[i];
it would give the following output:
10010010
simple enough and straight forward.
What I would like to do is to generate either a constexpr function, a function template, a lambda, or a combination of them that can run either during compile time or runtime depending on the context in which it is being used to where I could take each of these boolean values of 0s and 1s and store them into the variable value above. If the value is known at compile-time then I'd like for this assignment to be resolved. If the value isn't known at compile-time, then the value will be initialized to 0 until it is updated then it would be used in a runtime context.
However, there is one caveat that isn't obvious at first, but by indexing through the array, the 0th index of the array will be the LSB bit of the value and the 7th index will be the MSB. So the order of bits that you are seeing printed from the screen would have a hex value of 0x92 but the value to be stored needs to be 01001001 which would have the hex value of 0x49 or 73 in decimal and not 146.
The above are members in a class where one is the data value representation and the array of bools is the bit representation. I have a few constructors where one will set the data or value member directly and the other constructors will set the array of bools, but I need for both of these values to stay concurrent with each other through the life of the class object if one updates the other needs to be changed as well. Also, the array of bools is a member of a non-named union with a nameless struct of 8 individual bools as a single bit within a bit field. The class also has an index operator to access the individual bits as single boolean values of 0s or 1s.
Here is what my class looks like:
constexpr unsigned BIT_WIDTH(const unsigned bits = 8) { return bits; }
struct Register_8 {
union {
bool bits_[BIT_WIDTH()];
struct {
bool b0 : 1;
bool b1 : 1;
bool b2 : 1;
bool b3 : 1;
bool b4 : 1;
bool b5 : 1;
bool b6 : 1;
bool b7 : 1;
};
};
std::uint8_t data_;
Register_8() : data_{ 0 } {}
Register_8(std::uint8_t data) : data_{ data } {
}
Register_8(const bool bits[BIT_WIDTH()]) {
for (unsigned i = 0; i < 8; i++)
bits_[i] = bits[i];
}
Register_8(const bool a, const bool b, const bool c, const bool d,
const bool e, const bool f, const bool g, const bool h) {
b0 = a; b1 = b, b2 = c, b3 = d;
b4 = e, b5 = f, b6 = g, b7 = h;
}
const std::uint8_t operator[](std::uint8_t idx) {
// I know there is no bounds checking here, I'll add that later!
return bits_[idx];
}
};
So how can I make each of the values in bits[] to be the individual bits of value where bit[0] is the LSB of value? I would also like to do this in a context where it will not generate any UB! Or does there already exist an algorithm within the STL under c++17 that will do this for me? I don't have a C++20 compiler yet... I've tried including the std::uint8_t within the union but it doesn't work as I would like it too and I wouldn't expect it to work either!
I walked away for a little bit and came back to what I was working on... I think the short break had helped. The suggestion by user Nicol Bolas had also helped by letting me know that I can do it with a constexpr function. Now I don't have to worry about templates or lambdas for this part of the code.
Here is the function that I have came up with that I believe will assign the bits in the appropriate order.
constexpr unsigned BIT_WIDTH(const unsigned bits = CHAR_BIT) { return bits; }
constexpr std::uint8_t byte_from_bools(const bool bits[BIT_WIDTH()]) {
std::uint8_t ret = 0x00;
std::uint8_t pos = 0x00;
for (unsigned i = 0; i < BIT_WIDTH(); i++) {
ret |= static_cast<std::uint8_t>(bits[i]) << pos++; // << pos--;
}
return ret;
}
If there are any kind of optimizations that can be done or any bugs or code smells, please let me know...
Now, it's just a matter of extracting individual bits and assigning them to my bit-field members, and the track when either one changes to make sure both are updated in a concurrent fashion.
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.
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));
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 ;)