a method to do bit-operation in C - c

I'm trying to define a structure that can allow to set a byte value directly, and also allow to manipulate the bits of the byte without using function like bit_set(), bit_clear() etc,.
Here's my definition
typedef union FLAG_WORK {
volatile unsigned char BYTE;
struct {
volatile unsigned char bit0:1;
volatile unsigned char bit1:1;
volatile unsigned char bit2:1;
volatile unsigned char bit3:1;
volatile unsigned char bit4:1;
volatile unsigned char bit5:1;
volatile unsigned char bit6:1;
volatile unsigned char bit7:1;
}BIT;
}FLAG8;
and a sample code
int main()
{
FLAG8 i;
i.BYTE=(unsigned char)0; // initial the value of i.BYTE
i.BIT.bit0 = 1; // set bit0 of i.BYTE
i.BIT.bit1 = 1;
cout << (int)i.BYTE << endl;
cout << "Hello world!" << endl;
return 0;
}
I just wonder how to modify the structure allowing me to assign value to "i" in above code directly?
any suggestion?

C99 allows intializing members explicitly. Assuming I understand your question correctly, you're looking for
FLAG8 i = { .BIT = { .bit2 = 1, .bit5 = 1 } };
FLAG8 j = { .BYTE = 42 };
FLAG8 k = { 42 }; // same as j as initializing the first member is default

As normal you can assign like But the values are overlapped, because Here union holds only 1 byte of memory
FLAG8 i = { .BIT = { .bit2 = 1, .bit5 = 1 } , .BYTE = 42};
//result of i.BYTE is 42 depens on Byte value
FLAG8 i = { .BYTE = 42 , .BIT = { .bit2 = 1, .bit5 = 1 } };
//result of i.BYTE is 36 depends on bits values
1.As #Christoph suggested You can assign value BYTE or bit by bit directly Like this
FLAG8 i = { .BYTE = 42 };
FLAG8 j = { .BIT = { .bit2 = 1, .bit5 = 1 } };
printf("%d \n\n",(int)i.BYTE );
printf("%d \n\n",(int)j.BYTE );
2.You can assign value bit by bit
i.BIT.bit0 = 1; // set bit0 of i.BYTE
i.BIT.bit1 = 1;
i.BIT.bit4 = 1;
printf("%d \n\n",(int)i.BYTE );
3.You can assign directly a BYTE with hexa decimal value
i.BYTE=0x10;
printf("%d \n\n",(int)i.BYTE );
4.You can assign directly a BYTE with decimal value
i.BYTE=100;
printf("%d \n\n",(int)j.BYTE );
5.You can assign directly with the Identifier of same type
j.BYTE=0x30;
printf("%d \n\n",(int)j.BYTE );
i=j;
printf("%d \n\n",(int)i.BYTE );
6.Assign a decimal value and check it in printing both decimal and hexa decimal format
j.BYTE=100;
printf("%d \n\n",(int)j.BYTE );
printf("%x \n\n",(int)j.BYTE );
j.BIT.bit4=0;
j.BIT.bit5=0;
printf("%d \n\n",(int)j.BYTE );
printf("%x \n\n",(int)j.BYTE );

Related

printing variable after setting a bit

I am trying to set a bit in a 8 bit variable.
Every time I print the variable after setting a particular bit , I always get the value as 1.
uint8 value;
value = (1<<1 || value)
printf(%x \n,value); //prints 1 instead of 2
value = (1<<2 || value)
printf(%x \n,value); //prints 1 instead of 4
You're using boolean 'or' ||. Bitwise 'or' is |.
Also you haven't initialized value so you can't expect it to be anything.
No you don't do it like that.
To set a bit you OR with 1.
For example to set the least significant bit you OR with 1.
ie:
unsigned char val = 4;
// set bit 0
val |= 1;
printf("Value now: %x\n", val);
To set bit 1:
unsigned char val = 4;
// set bit 1
val |= 1 << 1;
printf("Value now: %x\n", val);
A complete example
#include <stdio.h>
char* get_binary(unsigned char buffer, char* binary) {
for (int i = 0; i < 8; ++i) {
int bit = (buffer >> i) & 1;
binary[7 - i] = bit ? '1' : '0';
}
return binary;
}
int main() {
unsigned char val = 4; // val now 100
int bits_to_shift;
unsigned char buffer[10] = { 0 };
unsigned char* p = buffer;
// set bit 0
val |= 1;
printf("Value now: %x, binary=%s\n", val, get_binary(val, p)); // val now 5 :- 101
// To set bit 1 (ie set so we have 111), shift to position then OR
// set bit 1
bits_to_shift = 1;
val |= 1 << bits_to_shift;
printf("Value now: %x, binary=%s\n", val, get_binary(val, p)); // val now 7 :- 111
// set bit 3
bits_to_shift = 3;
val |= 1 << bits_to_shift;
printf("Value now: %x, binary=%s\n", val, get_binary(val, p)); // val now F :- 1111
}

combining MSB and LSB in short

I have a function that return 1 Byte
uint8_t fun();
the function should run 9 times , so I get 9 Byte I want to make the last8 one as 4 short values here what I've done but I'm not sure that the value that I get are correct :
char array[9];
.............
for ( i = 0; i< 9 ; i++){
array[i] = fun();
}
printf( " 1. Byte %x a = %d , b=%d c =%d \n" ,
array[0],
*(short*)&(array[1]),
*(short*)&(array[3]),
*(short*)&(array[5]),
*(short*)&(array[7]));
is that right ?
It's better to be explicit and join the 8-bit values into 16-bit values yourself:
uint8_t bytes[9];
uint16_t words[4];
words[0] = bytes[1] | (bytes[2] << 8);
words[1] = bytes[3] | (bytes[4] << 8);
words[2] = bytes[5] | (bytes[6] << 8);
words[3] = bytes[7] | (bytes[8] << 8);
The above assumes little-endian, by the way.
You will get alignement problems. Any pointer to a short can be seen as a pointer to char, but on non 8 bit machines, the inverse is not guaranteed.
IMHO, this would be safer :
struct {
char arr0;
union {
char array[8];
uint16_t sarr[4];
} u;
} s;
s.arr0 = fun();
for ( i = 0; i< 8 ; i++){
s.u.array[i] = fun();
}
printf( " 1. Byte %x a = %d , b=%d c =%d d=%d\n" ,
s.arr0,
s.u.sarr[0],
s.u.sarr[1],
s.u.sarr[2],
s.u.sarr[3]);
But I suppose you deal correctly with endianness on your machine and know how the conversion 2 chars <=> 1 short works ...
Try using struct to arrange the data and shift operations to convert for enianism.
// The existence of this function is assumed from the question.
extern unsigned char fun(void);
typedef struct
{
unsigned char Byte;
short WordA;
short WordB;
short WordC;
short WordD;
} converted_data;
void ConvertByteArray(converted_data* Dest, unsigned char* Source)
{
Dest->Byte = Source[0];
// The following assume that the Source bytes are MSB first.
// If they are LSB first, you will need to swap the indeces.
Dest->WordA = (((short)Source[1]) << 8) + Source[2];
Dest->WordB = (((short)Source[3]) << 8) + Source[4];
Dest->WordC = (((short)Source[5]) << 8) + Source[6];
Dest->WordD = (((hshort)Source[7]) << 8) + Source[8];
}
int main(void)
{
unsigned char array[9];
converted_data convertedData;
// Fill the array as per the question.
int i;
for ( i = 0; i< 9 ; i++)
{
array[i] = fun();
}
// Perform the conversion
ConvertByteArray(&convertedData, array);
// Note the use of %h not %d to specify a short in the printf!
printf( " 1. Byte %x a = %h , b=%h c =%h d =%h\n",
(int)convertedData.Byte, // Cast as int because %x assumes an int.
convertedData.WordA,
convertedData.WordB,
convertedData.WordC,
convertedData.WordD );
return 0;
}

Character pointer to a union storage

I am trying to trace out the value at 1st byte of the union with the help of a char pointer.I assume that the output for byte1 should be ff but instead it's ffffffff.
Correct me If I am wrong.
#include <stdio.h>
#include <stdint.h>
#include <iostream>
struct TriggerMsg
{
uint32_t x[3];
uint32_t y[3];
};
struct sysData
{
union
{
TriggerMsg tTrigger;
uint8_t u8Wakeup;
uint8_t u8Reset;
}
u;
};
int main()
{
sysData sys;
for(int i =0 ; i<3 ; i++)
{
sys.u.tTrigger.x[i] = 0;
sys.u.tTrigger.y[i]= 0;
}
sys.u.u8Wakeup = 0xffffffff;
//sys.u.tTrigger = { 0 };
char *c = (char *)&(sys.u) ;
printf("u.tTrigger.x = %x \nu.tTrigger.y = %x \nu.u8Wakeup = %d \n\n" , \
sys.u.tTrigger.x[0], sys.u.tTrigger.y[0], sys.u.u8Wakeup);
for(int i=0; i<24;i++)
printf("Byte%d = %x \n", i, c[i]) ;
return 0;
}
Output:
u.tTrigger.x = ff
u.tTrigger.y = 0
u.u8Wakeup = 255
Byte0 = ffffffff
Byte1 = 0
Byte2 = 0
Byte3 = 0
Byte4 = 0
Byte5 = 0
Byte6 = 0
Byte7 = 0
Byte8 = 0
Byte9 = 0
Byte10 = 0
Byte11 = 0
Byte12 = 0
Byte13 = 0
Byte14 = 0
Byte15 = 0
Byte16 = 0
Byte17 = 0
Byte18 = 0
Byte19 = 0
Byte20 = 0
Byte21 = 0
Byte22 = 0
Byte23 = 0
I am trying to trace out the value at 1st byte of the union with the help of a char pointer.I assume that the output for byte1 should be ff but instead it's ffffffff.
Correct me If I am wrong.
The %x format prints unsigned ints, but your char is signed. It is promoted to a signed int when passed to printf. This leads to the unexpected output when the negative value in the signed integer is shown as though it were unsigned.
Change the char to unsigned char to fix this:
unsigned char *c = (unsigned char *)&(sys.u);
What you probably wanted is not char but unsigned char.
The first bit in a signed char indicates the sign, so there are only 7 bit left for the actual value. This results in interpreting 0xff as decimal -1 which is printed as hexadecimal 0xffffffff.
With an unsigned char everything is fine.

how to store 8 bits in char using C

what i mean is that if i want to store for example 11110011 i want to store it in exactly 1 byte in memory not in array of chars.
example:
if i write 10001111 as an input while scanf is used it only get the first 1 and store it in the variable while what i want is to get the whole value into the variable of type char just to consume only one byte of memory.
One way to write that down would be something like this:
unsigned char b = 1 << 7 |
1 << 6 |
1 << 5 |
1 << 4 |
0 << 3 |
0 << 2 |
1 << 1 |
1 << 0;
Here's a snippet to read it from a string:
int i;
char num[8] = "11110011";
unsigned char result = 0;
for ( i = 0; i < 8; ++i )
result |= (num[i] == '1') << (7 - i);
like this....
unsigned char mybyte = 0xF3;
Using a "bit field"?
#include <stdio.h>
union u {
struct {
int a:1;
int b:1;
int c:1;
int d:1;
int e:1;
int f:1;
int g:1;
int h:1;
};
char ch;
};
int main()
{
union u info;
info.a = 1; // low-bit
info.b = 1;
info.c = 0;
info.d = 0;
info.e = 1;
info.f = 1;
info.g = 1;
info.h = 1; // high-bit
printf("%d %x\n", (int)(unsigned char)info.ch, (int)(unsigned char)info.ch);
}
You need to calculate the number and then just store it in a char.
If you know how binary works this should be easy for you. I dont know how you have the binary data stored, but if its in a string, you need to go through it and for each 1 add the appropriate power of two to a temp variable (initialized to zero at first). This will yield you the number after you go through the whole array.
Look here: http://www.gidnetwork.com/b-44.html
Use an unsigned char and then store the value in it. Simple?
If you have read it from a file and it is in the form of a string then something like this should work:
char str[] = "11110011";
unsigned char number = 0;
for(int i=7; i>=0; i--)
{
unsigned char temp = 1;
if (str[i] == '1')
{
temp <<= (7-i);
number |= temp;
}
}

apply checksum in c to a char

How do you apply checkksum to a char in c?
A checksum reduces a sequence of bits to a shorter sequence, such that a change to the larger sequence results in a random change to the shorter checksum.
A char is already quite small. To produce a checksum you will need a bitfield. Actually, you will need two, since one bitfield alone will be padded at least to a full byte.
struct twochars_checksum {
unsigned sum_a : CHAR_BIT / 2;
unsigned sum_b : CHAR_BIT / 2;
};
void sum_char( char c, struct twochars_checksum *dest, int which ) {
int sum;
sum = c ^ c >> CHAR_BIT / 2; // suboptimal, but passable
if ( which == 0 ) {
dest->sum_a = sum;
} else {
dest->sum_b = sum;
}
}
Suggest to follow similar approach to transfer a byte of data with checksum.
The algorithm for calculating checksum is quite simple and is as follows.
1.Check if the bit is on then add the corresponding bit value ( ie 2 to the power of bit position ) to the check sum.
2.If the bit is off then detect the sum by 1.
Note : You can use your own checksum algorithm by altering function calculate_checksum().
You can include your own processing logic in set_transfer_data().
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define NUM_BITS (8)
uint16_t calculate_checksum(const uint8_t data)
{
uint16_t checksum = 0;
uint8_t bit_index = 0;
uint8_t bit_value = 0;
while( bit_index < NUM_BITS )
{
bit_value = 1 << bit_index++;
checksum += ( data & bit_value ) ? bit_value : -1;
}
return ( checksum );
}
uint8_t set_transfer_data( uint32_t *dest_data , const uint8_t src_data , const uint16_t checksum )
{
uint8_t return_value = 0;
*dest_data = checksum << NUM_BITS | src_data ;
return ( return_value );
}
int main()
{
uint8_t return_value = 0;
uint8_t source_data = 0xF3;
uint32_t transfer_data = 0;
uint16_t checksum = 0;
checksum = calculate_checksum( source_data );
printf( "\nChecksum calculated = %x",checksum );
return_value = set_transfer_data( &transfer_data,source_data,checksum );
if( 0 == return_value )
{
printf( "\nChecksum added successfully; transfer_data = %x",
transfer_data );
}
else
{
printf( "\nError adding checksum" );
}
return ( 0 );
}

Resources