Usage of bitset ?
-
My task is to modify selected bits in 8 bit (char) words. At present I have declared an array of two words. The array gets "filled" from hardware source - I2C adapter. I can manage to manipulate required bits using plain Boolean code - KISS. I have found this template class " bitset " . I have never used a template class and not sure if using it would be less code or confusion. Since I need to pass the char pointer of the array I am not sure if changing to template class would be as obvious as passing a char array pointer. I am open to suggestions. Cheers
-
My task is to modify selected bits in 8 bit (char) words. At present I have declared an array of two words. The array gets "filled" from hardware source - I2C adapter. I can manage to manipulate required bits using plain Boolean code - KISS. I have found this template class " bitset " . I have never used a template class and not sure if using it would be less code or confusion. Since I need to pass the char pointer of the array I am not sure if changing to template class would be as obvious as passing a char array pointer. I am open to suggestions. Cheers
The problem with a bitset is that you have no control over the internal representation of the bits. 1. There is no way to know whether the representation is 1 bit/value or 1 byte/value (this is a quality of implementation issue) 2. There is no way to know whether the underlying type is an array of chars, ints, or some other type 3. There is no way to know whether bit 0 is the MSB or the LSB of the underlying type If you are getting data from an external source, the only safe (and portable) way to read the data is as an array of char / unsigned char. Note that std::vector<> and std::array<> guarantee that the allocated memory will be contiguous, so a pointer to the zeroth element of either would be OK as well.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows. -- 6079 Smith W.
-
My task is to modify selected bits in 8 bit (char) words. At present I have declared an array of two words. The array gets "filled" from hardware source - I2C adapter. I can manage to manipulate required bits using plain Boolean code - KISS. I have found this template class " bitset " . I have never used a template class and not sure if using it would be less code or confusion. Since I need to pass the char pointer of the array I am not sure if changing to template class would be as obvious as passing a char array pointer. I am open to suggestions. Cheers
I suspect what you want to use is bit-field struct members. e.g. your device sends you 2 bytes, formatted as follows 1-2 op status code 1 3-6 op status code 2 7-12 error code 13-16 unused You could model that as follows
struct op_status {
unsigned int status_1:2;
unsigned int status_2:2;
unsigned int error:6;
};If you are unfamiliar with this construct a struct member like
unsigned int item:2
defines a member only 2 bits wide. The type of a bit-field member should be integral, (e.g. char, short, int, etc) but can be signed or unsigned as needed. You can use the struct members as short ints e.gint devfd = open("/dev/a_device", O_RDWR);
struct op_status i2c_status;
read(devfd, &i2c_status, sizeof(i2c_status));
if(i2c_status.status_1 == 1) {
/* do something */
} else if ( i2c_status.status_1 == 2 && i2c_status.status_2 = 1) {
switch(i2c_status.error) {
case 1: /* handle error code 1 */
break;
case 2: /* handle error code 2 */
break;
...
default: /* do something else */
}
}looking a , I don't see a nice way to group the bits together to treat them as a single unit, like you can using bit-fields. Usually, bit-fields are packed together, but check your compiler documentation to make sure. Also, don't forget that bit and/or byte order coming from your device might not match your CPU, so you may need to declare various fields out-of-order with respect to the documentation.
-
I suspect what you want to use is bit-field struct members. e.g. your device sends you 2 bytes, formatted as follows 1-2 op status code 1 3-6 op status code 2 7-12 error code 13-16 unused You could model that as follows
struct op_status {
unsigned int status_1:2;
unsigned int status_2:2;
unsigned int error:6;
};If you are unfamiliar with this construct a struct member like
unsigned int item:2
defines a member only 2 bits wide. The type of a bit-field member should be integral, (e.g. char, short, int, etc) but can be signed or unsigned as needed. You can use the struct members as short ints e.gint devfd = open("/dev/a_device", O_RDWR);
struct op_status i2c_status;
read(devfd, &i2c_status, sizeof(i2c_status));
if(i2c_status.status_1 == 1) {
/* do something */
} else if ( i2c_status.status_1 == 2 && i2c_status.status_2 = 1) {
switch(i2c_status.error) {
case 1: /* handle error code 1 */
break;
case 2: /* handle error code 2 */
break;
...
default: /* do something else */
}
}looking a , I don't see a nice way to group the bits together to treat them as a single unit, like you can using bit-fields. Usually, bit-fields are packed together, but check your compiler documentation to make sure. Also, don't forget that bit and/or byte order coming from your device might not match your CPU, so you may need to declare various fields out-of-order with respect to the documentation.
k5054 wrote:
looking a <bitset>, I don't see a nice way to group the bits together to treat them as a single unit, like you can using bit-fields.
All the usual logical and shift operators are defined on **bitset**s. You can also convert a bitset to an integer type, and construct a bitset from an integer type. The major issue is the internal representation, which is implementation-defined. This is why a bitset should not be used to interface to hardware.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows. -- 6079 Smith W.
-
I suspect what you want to use is bit-field struct members. e.g. your device sends you 2 bytes, formatted as follows 1-2 op status code 1 3-6 op status code 2 7-12 error code 13-16 unused You could model that as follows
struct op_status {
unsigned int status_1:2;
unsigned int status_2:2;
unsigned int error:6;
};If you are unfamiliar with this construct a struct member like
unsigned int item:2
defines a member only 2 bits wide. The type of a bit-field member should be integral, (e.g. char, short, int, etc) but can be signed or unsigned as needed. You can use the struct members as short ints e.gint devfd = open("/dev/a_device", O_RDWR);
struct op_status i2c_status;
read(devfd, &i2c_status, sizeof(i2c_status));
if(i2c_status.status_1 == 1) {
/* do something */
} else if ( i2c_status.status_1 == 2 && i2c_status.status_2 = 1) {
switch(i2c_status.error) {
case 1: /* handle error code 1 */
break;
case 2: /* handle error code 2 */
break;
...
default: /* do something else */
}
}looking a , I don't see a nice way to group the bits together to treat them as a single unit, like you can using bit-fields. Usually, bit-fields are packed together, but check your compiler documentation to make sure. Also, don't forget that bit and/or byte order coming from your device might not match your CPU, so you may need to declare various fields out-of-order with respect to the documentation.
Thanks, this will definitely give me a good start in using bitset, specially when I need to process more than two characters. Appreciate it. At current I have this code to process single char.
// build a common function to set / reset bits // shift data into correct bit postion cout << " data 0x" << hex << +data << endl; data <<= iLSbit; cout << " shifted data 0x" << hex << +data << endl; int iDataBit; for (int iBit = iLSbit; iBit != iMSbit + 1; iBit++) {
#ifdef DEBUG
cout << "processing bit " << dec << +iBit << endl;
// clear bit
buf[0] &= ~(1UL << iBit); // don't need this
#endif
// set or reset bit
// check data bit @ position
iDataBit = (data >> iBit) & 1U;
#ifdef DEBUG
cout << " iDataBit " << hex << +iDataBit << endl;
#endif
if (iDataBit) {
#ifdef DEBUG
cout << "set bit @ position " << dec << iBit << endl;
#endif
buf[0] |= (1UL << iBit);
} else {
#ifdef DEBUG
cout << "clear bit @ position " << dec << iBit << endl;
#endif
// clear bit
buf[0] &= ~(1UL << iBit);
}
}Since I need to read the data (hardware register ) before modifying it , then writing it back to hardware it seems simpler than using bitset. At present I am modifying / checking single register parameter ( A/D converter input MUX ) , but in future I like to modify all parameters in single access. I think that is where bitset will do the job. Thanks again Cheers Vaclav