both signed and unsigned as function parameter - c++

I have functions to read data from an EEPROM. When I want to read a short, regardless of it being signed or unsigned, I know I have to read 2 bytes. Same principle goes when I want to read an integer: I have to read 4 bytes, regardless of it being signed or unsigned.
Thus I wrote 4 functions: one that reads a short, one that reads an unsigned short, one that reads an int, one that reads an unsigned int, etc.
Usage looks like this :
// define a default value at zero
uint16_t API_PORT = 0;
// retrieve the API port, that would be between 0 to 65535, saved on the EEPROM
i2cReadUnsignedShortFromExternalEEPROM(I2C_ADDR_EEPROM, 12345, &API_PORT);
// the function
void i2cReadUnsignedShortFromExternalEEPROM(int i2cAddressOfExternalEEPROM, unsigned int atAdress, uint16_t *number) {
byte firstByte = i2cReadByteFromExternalEEPROM(i2cAddressOfExternalEEPROM, atAdress);
byte secondByte = i2cReadByteFromExternalEEPROM(i2cAddressOfExternalEEPROM, atAdress + 1);
*number = (firstByte << 8) + secondByte;
}
The function to read a SIGNED short is almost exactly the same, except the third parameter :
void i2cReadShortFromExternalEEPROM(int i2cAddressOfExternalEEPROM, unsigned int atAdress, short *number) {
byte firstByte = i2cReadByteFromExternalEEPROM(i2cAddressOfExternalEEPROM, atAdress);
byte secondByte = i2cReadByteFromExternalEEPROM(i2cAddressOfExternalEEPROM, atAdress + 1);
*number = (firstByte << 8) + secondByte;
}
Eventhough everything works fine, it bothers me as it introduces a lot of redundancy in my code.
Is there a way to refactor those two similar functions into just one?
The function would need to work in both following pseudocode scenarios :
unsigned short myUnsignedVar = 0;
myNewMethod(I2C_ADDR_EEPROM, 10, &myUnsignedVar);
// myUnsignedVar now holds value of 65000
signed short mySignedVar = 0;
myNewMethod(I2C_ADDR_EEPROM, 12, &mySignedVar);
// mySignedVar now holds value of -123
In other words, I want to make it so that the function accepts both signed and unsigned as 3rd parameter.
I'm new to C++

Following #Taekahn 's comment regarding function templates, my function now looks like this :
template <typename T>
void i2cReadShortFromExternalEEPROM(int i2cAddressOfExternalEEPROM, unsigned int atAddress, T *number) {
byte firstByte = i2cReadByteFromExternalEEPROM(i2cAddressOfExternalEEPROM, atAddress);
byte secondByte = i2cReadByteFromExternalEEPROM(i2cAddressOfExternalEEPROM, atAddress + 1);
*number = (firstByte << 8) + secondByte;
}
It seems to work fine (tested).
Example of usage :
i2cReadShortFromExternalEEPROM<uint16_t>(I2C_ADDR_EEPROM, some_page, &API_PORT); // 443
i2cReadShortFromExternalEEPROM<short>(I2C_ADDR_EEPROM, some_page, &DEPTH); // -12345
Thank you for your guidance.

Related

2 int8_t's to uint16_t and back

I want to support some serial device in my application.
This device is used with another program and I want to interact with both the device and the save files this program creates.
Yet for some yet to be discovered reason, weird integer casting is going on.
The device returns uint8's over a serial USB connection, the program saves them as int8 to a file and when you read the file, you need to combine 2 int8's to a single uint16.
So when writing the save-file after reading the device, i need to convert an int8 to uint8, resulting in any value higher then 127 to be written as a negative.
Then when I read the save file, I need to combine 2 int8's into a single uint16.
(So convert the negative value to positive and then stick them together)
And then when I save to a save file from within my application, I need to split my uint16 into 2 int8's.
I need to come up with the functions "encode", "combine" and "explode"
// When I read the device and write to the save file:
uint8_t val_1 = 255;
int8_t val_2 = encode(val_1);
REQUIRE(-1 == val_2);
// When I read from the save file to use it in my program.
int8_t val_1 = 7;
int8_t val_2 = -125;
uint16_t val_3 = combine(val_1, val_2);
REQUIRE(1923 == val_3);
// When I export data from my program to the device save-file
int8_t val_4;
int8_t val_5;
explode(val_3, &val_1, &val_2);
REQUIRE(7 == val_4);
REQUIRE(-125 == val_5);
Can anyone give me a head start here?
Your encode method can just be an assignment. Implicit conversion between unsigned integer types and signed integer types is well defined.
uint8_t val_1 = 255;
int8_t val_2 = val_1;
REQUIRE(-1 == val_2);
As for combine - you'll want to cast your first value to a uint16_t to ensure you have enough bits available, and then bitshift it left by 8 bits. This causes the bits from your first value to make up the 8 most significant bits of your new value (the 8 least significant bits are zero). You can then add your second value, which will set the 8 least significant bits.
uint16_t combine(uint8_t a, uint8_t b) {
return ((uint16_t)a << 8) + b;
}
Explode is just going to be the opposite of this. You need to bitshift right 8 bits to get the first output value, and then just simply assign to get the lowest 8 bits.
void explode(uint16_t from, int8_t &to1, int8_t &to2) {
// This gets the lowest 8 bits, and implicitly converts
// from unsigned to signed
to2 = from;
// Move the 8 most significant bits to be the 8 least
// significant bits, and then just assign as we did
// for the other value
to1 = (from >> 8);
}
As a full program:
#include <iostream>
#include <cstdint>
using namespace std;
int8_t encode(uint8_t from) {
// implicit conversion from unsigned to signed
return from;
}
uint16_t combine(uint8_t a, uint8_t b) {
return ((uint16_t)a << 8) + b;
}
void explode( uint16_t from, int8_t &to1, int8_t &to2 ) {
to2 = from;
to1 = (from >> 8);
}
int main() {
uint8_t val_1 = 255;
int8_t val_2 = encode(val_1);
assert(-1 == val_2);
// When I read from the save file to use it in my program.
val_1 = 7;
val_2 = -125;
uint16_t val_3 = combine(val_1, val_2);
assert(1923 == val_3);
// When I export data from my program to the device save-file
int8_t val_4;
int8_t val_5;
explode(val_3, val_4, val_5);
assert(7 == val_4);
assert(-125 == val_5);
}
For further reading on bit-manipulation mechanics, you could take a look here.

How to do bitmasking for unsigned long int?

I am working on branch predicter implementation in that I need to create a Branch history register (BHR) which stores 1111 into the first 4 bits of an unsigned int, after every prediction. We will get output from Finite-state machine and that is updated into the BHR using left-shift. Can you explain for me how to do that?
Here's what I've tried:
struct BHR
{
long int BHR_index;
unsigned input = 0b1111u, n_bits = 4u, *bits =new unsigned[n_bits], bit = 0;
};
int main(int argc, char** argv)
{
long int table_size = 1227;
BHR *table = new BHR[table_size];
for(int k = 0;k<=table_size;k++)
{
for(table->bit = 0; table ->bit < table ->n_bits; ++table->bit)
table[k].bits[table -> bit] = (table -> input >> table ->bit)&1;
}
free(table->bits);
}
I did bit masking like this but I am getting thread 1: EXC_BAD_ACCESS (code=1, address=0x0) error in Xcode. Can anyone please help me.
If by "starting 4 bits" you mean the low (least significant) 4 bits, then this mask will clear all others, leaving those 4 bits intact:
unsigned long int someValue = 12345;
unsigned long int low4bits = someValue & 0xF;
This AND mask (& operator) works by clearing all bits in the destination that aren't set in both operands. So, as the value of 0xF in binary is ...0001111, all other bits will be cleared.
If you want the high (most significant) 4 bits, then you need to know the size of unsigned long int (although see below). If (as is common) this is 32-bits, then the mask you need will be as follows:
unsigned long int someValue = 12345;
unsigned long int high4bits = someValue & 0xF0000000;
Feel free to ask for further explanation and/or clarification.
EDIT:
Actually, there is a way to get the mask for the high 4 bits of an unsigned long int even if you don't know its actual size, but it maybe a bit confusing. The code below is not the most 'efficient' way, perhaps; rather, it is designed to illustrate the process:
unsigned long int zeroValue = 0; // All bits are clear.
unsigned long int notZero = ~zeroValue; // ~ inverts all bits, so now all set
unsigned long int top4Clear = notZero >> 4; // shift set bits by 4, and zero-pad top 4
unsigned long int top4Mask = ~top4Clear; // Again, the ~ operator inverts all bits
With this top4Mask value, we can now clear all but the high (most significant) bits:
unsigned long int someValue = 12345;
unsigned long int high4bits = someValue & top4Mask;
Another way is to use bit-fields that do the bit masking for you:
struct ulong4b {
unsigned long value : 4;
};
int main() {
ulong4b a;
a.value = 1; // Stores the lower 4 bits only.
unsigned long value = a.value; // Reads the lower 4 bits only.
}
I think that this macro will help you if you want to extract bits from a number :
#define GET_BITS(number, offbits, nbits) (((number) >> (offbits)) & ((1 << (nbits)) - 1))
int x = 12345;
int last4bits = GET_BITS(x, 0, 4); // last4bits = x & 0x0000000F;
int first4bits = GET_BITS(x, 32 - 4, 4); // first4bits = x & 0xF0000000;

Extracting continuos bits from a std::string bytewise with a bit offset

I'm kind of at a loss i want to extract up to 64bits with a defined bitoffset and bitlength (unsigned long long) from a string (coming from network).
The string can be at an undefined length, so i need to be sure to only access it Bytewise. (Also means i cant use _bextr_u32 intrinsic). I cant use the std bitset class because it doesnt allow extraction of more then one bit with an offset and also only allows extraction of a predefined number of bits.
So I already calculate the byteoffset (within the string) and bitoffset (within the starting byte).
m_nByteOffset = nBitOffset / 8;
m_nBitOffset = nBitOffset % 8;
Now i can get the starting address
const char* sSource = str.c_str()+m_nByteOffset;
And the bitmask
unsigned long long nMask = 0xFFFFFFFFFFFFFFFFULL >> (64-nBitLen);
But now I just cant figure out how to extract up to 64 bits from this as there are no 128 bit integers available.
unsigned long long nResult = ((*(unsigned long long*)sSource) >> m_nBitOffset) & nMask;
This only works for up to 64-bitoffset bits, how can i extend it to really work for 64 bit indepently of the bitoffset. And also as this is not a bytewise access it could cause a memory read access violation.
So im really looking for a bytewise solution to this problem that works for up to 64 bits. (preferably C or intrinsics)
Update: After searching and testing a lot I will probably use this function from RakNet:
https://github.com/OculusVR/RakNet/blob/master/Source/BitStream.cpp#L551
To do it byte-wise, just read the string (which BTW it is better to interpret as a sequence of uint8_t rather than char) one byte at a time, updating your result by shifting it left 8 and oring it with the current byte. The only complications are the first bit and the last bit, which both require you to read a part of a byte. For the first part simply use a bit mask to get the bit you need, and for the last part down shift it by the amount needed. Here is the code:
const uint8_t* sSource = reinterpret_cast<const uint8_t*>(str.c_str()+m_nByteOffset);
uint64_t result = 0;
uint8_t FULL_MASK = 0xFF;
if(m_nBitOffset) {
result = (*sSource & (FULL_MASK >> m_nBitOffset));
nBitLen -= (8 - m_nBitOffset);
sSource++;
}
while(nBitLen > 8) {
result <<= 8;
result |= *sSource;
nBitLen -= 8;
++sSource;
}
if(nBitLen) {
result <<= nBitLen;
result |= (*sSource >> (8 - nBitLen));
}
return result;
This is how I would do it in modern C++ style.
The bit length is determined by the size of the buffer extractedBits: instead of using an unsigned long long, you could also use any other data type (or even array type) with the desired size.
See it live
unsigned long long extractedBits;
char* extractedString = reinterpret_cast<char*>(&extractedBits);
std::transform(str.begin() + m_nByteOffset,
str.begin() + m_nByteOffset + sizeof(extractedBits),
str.begin() + m_nByteOffset + 1,
extractedString,
[=](char c, char d)
{
char bitsFromC = (c << m_nBitOffset);
char bitsFromD =
(static_cast<unsigned char>(d) >> (CHAR_BIT - m_nBitOffset));
return bitsFromC | bitsFromD;
});

having char[1] and offset how to read int?

I have such structure
typedef struct {
int32_t DataLen;
char Data[1];
} MTEMSG;
So Data contains DataLen symbols that should be decoded by certain rules. I should write ReadInt ReadString etc methods.
As a first step I want to write ReadInt. From documentation this is "Four bytes in a format of x86 CPU (the little-endian byte goes first)." How can I convert char[1] to int? I guess it should be something like:
MTEMSG* data;
int offset;
....
int Reader::ReadInt()
{
int result = // read 4 bytes starting from offset
offset += 4;
}
It's allowed to use boost and c++11. Just looking for simple and fast method to convert.
I hope once you suggest me how to convert int I can do many of the rest methods myself.
Totally illegal and UB, but you would do something like *reinterpret_cast<int*>(data+offset).
Watch out for alignment and stuff.
First of all, in C++ as they have stated in the comments, this is illegal. Nevertheless, assuming your compiler assumes you might do something like this and has a well-defined behavior for it, then let's go ahead.
So semantically, you have such a struct:
typedef struct {
int32_t DataLen;
char Data[N];
} MTEMSG;
where N is "large enough".
And you need to convert Data to a 4-byte little endian integer. That's quite simple:
MTEMSG* data;
int offset = 0;
....
int Reader::ReadInt()
{
/* Note: int32_t would be more precise */
int result = data->Data[offset + 0]
| (data->Data[offset + 1] << 8)
| (data->Data[offset + 2] << 16)
| (data->Data[offset + 3] << 24);
offset += 4;
}

Getting the size of an indiviual field from a c++ struct field

The short version is: How do I learn the size (in bits) of an individual field of a c++ field?
To clarify, an example of the field I am talking about:
struct Test {
unsigned field1 : 4; // takes up 4 bits
unsigned field2 : 8; // 8 bits
unsigned field3 : 1; // 1 bit
unsigned field4 : 3; // 3 bits
unsigned field5 : 16; // 16 more to make it a 32 bit struct
int normal_member; // normal struct variable member, 4 bytes on my system
};
Test t;
t.field1 = 1;
t.field2 = 5;
// etc.
To get the size of the entire Test object is easy, we just say
sizeof(Test); // returns 8, for 8 bytes total size
We can get a normal struct member through
sizeof(((Test*)0)->normal_member); // returns 4 (on my system)
I would like to know how to get the size of an individual field, say Test::field4. The above example for a normal struct member does not work. Any ideas? Or does someone know a reason why it cannot work? I am fairly convinced that sizeof will not be of help since it only returns size in bytes, but if anyone knows otherwise I'm all ears.
Thanks!
You can calculate the size at run time, fwiw, e.g.:
//instantiate
Test t;
//fill all bits in the field
t.field1 = ~0;
//extract to unsigned integer
unsigned int i = t.field1;
... TODO use contents of i to calculate the bit-width of the field ...
You cannot take the sizeof a bitfield and get the number of bits.
Your best bet would be use #defines or enums:
struct Test {
enum Sizes {
sizeof_field1 = 4,
sizeof_field2 = 8,
sizeof_field3 = 1,
sizeof_field4 = 3,
sizeof_field5 = 16,
};
unsigned field1 : sizeof_field1; // takes up 4 bits
unsigned field2 : sizeof_field2; // 8 bits
unsigned field3 : sizeof_field3; // 1 bit
unsigned field4 : sizeof_field4; // 3 bits
unsigned field5 : sizeof_field5; // 16 more to make it a 32 bit struct
int normal_member; // normal struct variable member, 4 bytes on my system
};
printf("%d\n", Test::sizeof_field1); // prints 4
For the sake of consistency, I believe you can move normal_member up to the top and add an entry in Sizes using sizeof(normal_member). This messes with the order of your data, though.
Seems unlikely, since sizeof() is in bytes, and you want bits.
http://en.wikipedia.org/wiki/Sizeof
building on the bit counting answer, you can use.
http://www-graphics.stanford.edu/~seander/bithacks.html
Using ChrisW's idea (nice, by the way), you can create a helper macro:
#define SIZEOF_BITFIELD(class,member,out) { \
class tmp_; \
tmp_.member = ~0; \
unsigned int tmp2_ = tmp_.member; \
++tmp2_; \
out = log2(tmp2_); \
}
unsigned int log2(unsigned int x) {
// Overflow occured.
if(!x) {
return sizeof(unsigned int) * CHAR_BIT;
}
// Some bit twiddling... Exploiting the fact that floats use base 2 and store the exponent. Assumes 32-bit IEEE.
float f = (float)x;
return (*(unsigned int *)&f >> 23) - 0x7f;
}
Usage:
size_t size;
SIZEOF_BITFIELD(Test, field1, size); // Class of the field, field itself, output variable.
printf("%d\n", size); // Prints 4.
My attempts to use templated functions have failed. I'm not an expert on templates, however, so it may still be possible to have a clean method (e.g. sizeof_bitfield(Test::field1)).
I don't think you can do it. If you really need the size, I suggest you use a #define (or, better yet, if possible a const variable -- I'm not sure if that's legal) as so:
#define TEST_FIELD1_SIZE 4
struct Test {
unsigned field1 : TEST_FIELD1_SIZE;
...
}
This is not possible
Answer to comment:
Because the type is just an int, there is no 'bit' type. The bit field assignment syntax is just short hand for performing the bitwise code for reads and writes.