Zero specific bit without bitmask? [duplicate] - c

This question already has answers here:
How do I set, clear, and toggle a single bit?
(27 answers)
Closed 9 months ago.
I'd like to set a specific bit to 0 but without using a bitmask because I'm using enums and if the enum values change, enum fields get moved around then the bitmask would no longer be valid.
I can toggle a bit on, using a temporary variable then OR it with the already existing bitfield
#include <assert.h>
enum EState{
k_EStateNone,// bit 1 - 1
k_EStateFoo,// bit 2 - 10
k_EStateBar// bit 3 - 100
};
uint64_t togglebiton(uint64_t state,EState ebit){
uint64_t temp = 1<<ebit;
state|=temp;
return state;
}
int main(){
uint64_t state = 0;
state = togglebiton(state, k_EStateBar);
state = togglebiton(state, k_EStateFoo);
//foo bar = 110 == 6
assert(state == 6);
return 0;
}
But I'm unsure how to go about flipping the bit off, because I can't AND the whole thing with 0..

To flip a bit off, first shift the bit to the desired location, then use a bitwise NOT to invert all bits so that all but the target bit is set, then do a bitwise AND.
uint64_t togglebitoff(uint64_t state,EState ebit){
uint64_t temp = 1ULL<<ebit;
state&=~temp;
return state;
}
Also make sure that the constant you're shifting is of the correct type so that you don't shift into the sign bit of a signed type or more than the bit width of the type in question.

Related

How to cast 10 bit sign integer to 16 bit integer in C

I am parsing a data which is a 10 bit signed integer. Since the only way to represent this data is to either use int or short ( for sign 2-byte representation), I have to cast 10 bit to 16 bit.
I have applied 2 methods already but they are either slow or compiler depended.
The slow method is to use pow() function
value = pow(2,16) - pow(2,10) + value
The compiler dependent method is
value = (value << 6) >> 6 (right shift shifts the MSB which is a compiler dependent operation and may shift 0 if compiler is different)
Can someone help me find the standar way of casting non standard types to standard types
Here is the logic for the operations explicitly written out. Obviously you can do this with a one-liner, but I hope this explains why.
#include <stdio.h>
#include <string.h>
#include <stdint.h>
int main(int argc, char* argv[]) {
//int16_t value = 0x3fdb; // random examples
//int16_t value = 0x00f3;
int16_t value = 0x3f3;
printf("0x%04x (%i)\n", value, value); // in
uint16_t mask = 0x3ff; // 0000 0011 1111 1111 in binary
uint16_t masked = value & mask; // get only the 10 LSB
uint16_t extension = (0x200 & value) ? 0xFC00 : 0x0; // extend with 1s or 0s
printf("extension: %i\n", (extension)?1:0);
int16_t extended = extension | masked; // do the extension
printf("0x%04x (%i)\n", extended, extended); // out
return 0;
}
Examples:
0x00f3 (243)
extension: 0
0x00f3 (243)
0x3fdb (16347)
extension: 1
0xffffffdb (-37)
0xfffffff3 (-13)
extension: 1
0xfffffff3 (-13)
0x03f3 (1011)
extension: 1
0xfffffff3 (-13)
value = value & 0x03FF; //mask off the high 6 bits like you want.
There should be no 10 bit integers, i assume value is a short but you should add that relevant info.
edit
If you only want to mask if the 10th bit is set then:
value = (value & 0x0200) ? (value & 0x03FF) : value;

Most elegant way of turning bits on and off [duplicate]

This question already has answers here:
How do I set, clear, and toggle a single bit?
(27 answers)
Closed 3 years ago.
I've got a register which can either be 0x02 or 0x01 (0010 or 0001). What is the most elegant way of setting the bits in a single operation? E.g. if the register is currently 0x02, I need to turn off bit 2 and turn on bit 1.
Many thanks
x ^= 3 changes 1 to 2 and changes 2 to 1. ^ performs an exclusive or (XOR) operation.
The most elegant way is to define a structure that uses bit fields. Sadly this is rarely appropriate when dealing with hardware registers (e.g. order of bits in a bit-field isn't well defined, etc).
Without bitfields; use "and with compliment" (e.g. x = x & ~ 2; or x &= ~2;) to clear bits and "or" (e.g. x = x | 1; or x |= 1;) to set bits.
If you know the previous value you can optimize further. For example, if you know the previous value is 0x02 then you can just set a new value (e.g. x = 0x01; // It was 0x02 or maybe x = (0x02 & ~2) | 1; so compiler will work out the constant for you but the source code still reflects how the constant was determined).
Note that it's not possible to do it in a single operation unless you do know something about the previous value. For example, if you know that the previous value will have bit 0 clear and bit 1 set but don't know anything about the other bits (and need to preserve the other bits), then you can decrement (x--; // Clear bit 2, set bit 1) or use exclusive OR.

Bitmask - Left shift overflow [duplicate]

This question already has answers here:
Algorithm to generate bit mask
(9 answers)
Closed 4 years ago.
Problem:
I want to generate a Bit mask (uint32_t) based on a given length.
Following result should be achieved:
BIT_MASK(3) = 0x00..0111
BIT_MASK(32) = 0x111..111
The code given below is working for every length smaller than 32. If the length is 32, the left shift count is larger than the type width (overflow).
#define BIT(n) ( 1<<(n) )
#define BIT_MASK(len) ( BIT(len)-1 )
uint32_t length;
uint32_t mask = BIT_MASK(length);
Question:
Is there any other efficient macro solution to generate a Bit mask, which is not including an additional if/else or typecast to avoid that error.
This is pretty much it, but you need to change the literal 1 to 1UL. Otherwise you are restricted to the range of int, which is likely 31 bits instead of 32.
#define BIT_MASK32(n) ( (1UL<<(n)) - 1UL )
Where n must be in the range of 0 to 31 to fit a uint32_t. To safe guard against overflow, you could make it (n)%32, though that will make the macro slower if n is a run-time value rather than an integer constant.

Calculate bitmask from a given index in a 16 bit architecture

I have a function that accepts an index variable of type unsigned long (this type cannot be changed).
void func(unsigned long index);
I need to convert it to a bitmask such that for index 0 the bitmask will be 1, for index 1 bitmask will be 2, for 2 it will be 4 and so on.
I have done the following:
mask = 1 << index;
The problem is that I'm working with an architecture of 16 bit , therefore unsigned long variables are shown as 32 bit which messes up this variable.
(the lowest 16 bits give me the correct value for mask but the highest 16 bits add extra information which messes this up).
i.e. Instead of getting: mask = 0000000000000001 (16 bit)
I'm getting: xxxxxxxxxxxxxxxx0000000000000001 (32 bits)
Is there another way to calculate this bitmask?
Would appreciate help.
Thank you.
You have the correct approach. However, the problem with your implementation is that the type of 1 in 1 << index expression is int, with implementation-defined representation. Since you are looking for an unsigned long result, use ((unsigned long)1) instead:
unsigned long mask = ((unsigned long)1) << index;
If your platform supports stdint.h and you need a mask of some specific width, use uint32_t instead:
uint32_t mask = UINT32_C(1) << index;
Your basic code is correct, although I notice you didn't specify the type of mask.
If the caller passes a value greater than 15 into index, what are you going to do? It sounds like you have to make the most of a bad situation. Depending on the context you could simply return from func, you could assert, or you could proceed with a mask of zero.
This brings us back to the question of the type of mask. I would define it as unsigned short, uint16 or similar, depending on your environment. But other than that, your first attempt was basically correct. It's just a question of error handling.
uint16 shift = index & 15;
uint16 mask = 1 << shift;

Storing a 4-bit value in the middle of an 8-bit register

I need to count from 0 to 10 and store those values in binary format in ADCON0(5:2). How do I point at bit 5 of this register? Bit 5 is named ADCON0bits.CHS3. If I store a 4 bit variable to ADCON0bits.CHS3, will bits 1 - 3 be written to bits 4 - 2 of the register?
Also, are there any 4 bit data types that I could use?
This is all on a PIC microcontroller.
Edit: I need to store 4 bits in the register like so:
unsigned char count = 10 //max value
[X][X][1][0][1][0][X][X]
This is in line with what was assumed below, but I figured I would clear up my question a bit.
When you say you are writing bits 1-3 of your count into positions 4-2 of your register, do you explicitly mean you are reversing the order of the bits? In this answer I will presume that that was not what you meant.
You can express a bit field explicitly as a struct.
Presuming that you are dealing with a 16 bit register, your struct could look something like this:
struct adcon {
unsigned char someflag : 2;
unsigned char count : 4;
unsigned char other_bits : 2;
};
With each struct member, you specify the number of bits. Then you can operate on the appropriate bits in the register by casting the register to the struct type, and operating on the members of the struct.
(adcon) ADCON0.count = count;
Edit: fixed up the code based on feedback, thanks.
Writing to a bit variable stores the truth value of that variable to the bit. For example, writing:
ADCON0bits.CHS3 = 3;
will set that bit to 1.
If bit5 refers to the bit masked by 0x20 (00100000) and you need to store the 4 bit number in bits masked 0x3c (00111100) then you can use bit shifts and bitwise operations:
// First clear bits 1-5:
ADCON0 &= ~0x3c;
// Now set the bits to correct value:
ADCON0 |= (count << 2); // <-- remember to shift 2 bits to the left
update: As mentioned by Ian in the comments. This sets ADCON0 to an intermediate value before updating. In this case it is OK since it is only selecting the A/D channel and not actually executing the conversion. But in general it's better to do:
unsigned char temp_adcon;
temp_adcon = ADCON0 & ~0x3c;
ADCON0 = temp_adcon | (count << 2);
See the answers for this SO question.
Note that you are doing a read-modify-write operation. You have to be careful of race conditions when doing this. Race conditions may be caused by:
The hardware itself changing bits in the register (e.g. A/D converter operation completes and sets flags). The design of the hardware should provide a means for you to avoid this problem—there are several possible solutions—read the manual for the micro/peripheral to find out.
Your own interrupt routine(s) also writing to the register. If so, when your main (non-interrupt) code writes to the register, it should be done within an "interrupts disabled" context.
I'm not sure about the exact register ADCON0, but often you can read the register, mask the 4 bits and insert your count and then use that value to write back to the register.
Just in case, masking is performed with an AND operation and inserting is an OR operation with the count shift over 2 bits in your case.

Resources