Extract a bit sequence from a character - c

So I have an array of characters like the following {h,e,l,l,o,o}
so I need first to translate this to its bit representation, so what I would have is this
h = 01101000
e = 01100101
l = 01101100
l = 01101100
o = 01101111
o = 01101111
I need divide all of this bits in groups of five and save it to an array
so for example the union of all this characters would be
011010000110010101101100011011000110111101101111
And now I divide this in groups of five so
01101 00001 10010 10110 11000 11011 00011 01111 01101 111
and the last sequence should be completed with zeros so it would be 00111 instead. Note: Each group of 5 bits would be completed with a header in order to have 8 bits.
So I havent realized yet how to accomplish this, because I can extract the 5 bits of each character and get the representation of each character in binary as following
for (int i = 7; i >= 0; --i)
{
printf("%c", (c & (1 << i)) ? '1' : '0');
}
The problem is how to combine two characters so If I have two characters 00000001 and 11111110 when I divide in five groups I would have 5 bits of the first part of the character and for the second group I would have 3 bits from the last character and 2 from the second one. How can I make this combination and save all this groups in an array?

Assuming that a byte is made of 8 bits (ATTENTION: the C standard doesn't guarantee this), you have to loop over the string and play with bit operations to get it done:
>> n right shift to get rid of the n lowest bits
<< n to inject n times a 0 bit in the lowest position
& 0x1f to keep only the 5 lowest bits and reset the higer bits
| to merge high bits and low bits, when the overlapping bits are 0
This can be coded like this:
char s[]="helloo";
unsigned char last=0; // remaining bits from previous iteration in high output part
size_t j=5; // number of high input bits to keep in the low output part
unsigned char output=0;
for (char *p=s; *p; p++) { // iterate on the string
do {
output = ((*p >> (8-j)) | last) & 0x1f; // last high bits set followed by j bits shifted to lower part; only 5 bits are kept
printf ("%02x ",(unsigned)output);
j += 5; // take next block
last = (*p << (j%8)) & 0x1f; // keep the ignored bits for next iteration
} while (j<8); // loop if second block to be extracted from current byte
j -= 8;
}
if (j) // there are trailing bits to be output
printf("%02x\n",(unsigned)last);
online demo
The displayed result for your example will be (in hexadecimal): 0d 01 12 16 18 1b 03 0f 0d 1c, which corresponds exactly to each of the 5 bit groups that you have listed. Note that this code ads 0 right padding in the last block if it is not exactly 5 bits long (e.g. here the last 3 bits are padded to 11100 i.e. 0x1C instead of 111 which would be 0x0B)
You could easily adapt this code to store the output in a buffer instead of printing it. The only delicate thing would be to precalculate the size of the output which should be 8/5 times the original size, to be increased by 1 if it's not a multiple of 5 and again by 1 if you expect a terminator to be added.

Here is some code that should solve your problem:
#include <stdio.h>
#include <string.h>
int main(void)
{
char arr[6] = {'h', 'e', 'l', 'l', 'o', 'o'};
char charcode[9];
char binarr[121] = "";
char fives[24][5] = {{0}};
int i, j, n, numchars, grouping = 0, numgroups = 0;
/* Build binary string */
printf("\nCharacter encodings:\n");
for (j = 0; j < 6; j++) {
for (i = 0, n = 7; i < 8; i++, n--)
charcode[i] = (arr[j] & (01 << n)) ? '1' : '0';
charcode[8] = '\0';
printf("%c = %s\n", arr[j], charcode);
strcat(binarr, charcode);
}
/* Break binary string into groups of 5 characters */
numchars = strlen(binarr);
j = 0;
while (j < numchars) {
i = 0;
if ((numchars - j) < 5) { // add '0' padding
for (i = 0; i < (5 - (numchars - j)); i++)
fives[grouping][i] = '0';
}
while (i < 5) { // write binary digits
fives[grouping][i] = binarr[j];
++i;
++j;
}
++grouping;
++numgroups;
}
printf("\nConcatenated binary string:\n");
printf("%s\n", binarr);
printf("\nGroupings of five, with padded final grouping:\n");
for (grouping = 0; grouping <= numgroups; grouping++) {
for (i = 0; i < 5; i++)
printf("%c", fives[grouping][i]);
putchar(' ');
}
putchar('\n');
return 0;
}
When you run this as is, the output is:
Character encodings:
h = 01101000
e = 01100101
l = 01101100
l = 01101100
o = 01101111
o = 01101111
Concatenated binary string:
011010000110010101101100011011000110111101101111
Groupings of five, with padded final grouping:
01101 00001 10010 10110 11000 11011 00011 01111 01101 00111

#include <limits.h>
#include <stdio.h>
#define GROUP_SIZE 5
static int nextBit(void);
static int nextGroup(char *dest);
static char str[] = "helloo";
int main(void) {
char bits[GROUP_SIZE + 1];
int firstTime, nBits;
firstTime = 1;
while ((nBits = nextGroup(bits)) == GROUP_SIZE) {
if (!firstTime) {
(void) putchar(' ');
}
firstTime = 0;
(void) printf("%s", bits);
}
if (nBits > 0) {
if (!firstTime) {
(void) putchar(' ');
}
while (nBits++ < GROUP_SIZE) {
(void) putchar('0');
}
(void) printf("%s", bits);
}
(void) putchar('\n');
return 0;
}
static int nextBit(void) {
static int bitI = 0, charI = -1;
if (--bitI < 0) {
bitI = CHAR_BIT - 1;
if (str[++charI] == '\0') {
return -1;
}
}
return (str[charI] & (1 << bitI)) != 0 ? 1 : 0;
}
static int nextGroup(char *dest) {
int bit, i;
for (i = 0; i < GROUP_SIZE; ++i) {
bit = nextBit();
if (bit == -1) {
break;
}
dest[i] = '0' + bit;
}
dest[i] = '\0';
return i;
}

Related

C: How to use decimal number in hex one to one?

I want to "convert" a decimal number to a hex number. Not like 10 -> A.
E.g.: 10 -> 0x10, 55 -> 0x55, 2021 -> 0x2021, ...
My input is an int.
I already heard something about it. You can get the first digit with modulo 10. E.g. 55 % 10 is 5. But I don't know how to get the other digits and how to put it together.
I am using this function for other purpose but I did some changes and its work fine.
you can use this :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define CHECK_ALPHA_HEX(REC_CHAR) (unsigned)('#' < REC_CHAR && REC_CHAR < 'G')
#define CHECK_NUM(REC_CHAR) (unsigned)('/' < REC_CHAR && REC_CHAR < ':')
void DEC_TO_HEX(int in, int *outval ) {
uint8_t tbuff[5];
uint8_t chr_count = 0;
uint8_t len = sprintf(tbuff,"%d",in);
while(chr_count < len) {
tbuff[chr_count] -= CHECK_NUM(tbuff[chr_count]) ? '0' : CHECK_ALPHA_HEX(tbuff[chr_count]) ? '7' : tbuff[chr_count];
*outval |= (tbuff[chr_count] << (4 *((len-1) - chr_count)));
chr_count++;
}
}
int main() {
int out = 0;
int in = 2021;
DEC_TO_HEX(in,&out);`
printf("%x",out);
}
https://godbolt.org/z/8T9Wqb87n
how to get the other digits
Remove the extracted digit from input.
Repeat the extraction of one digit, until there are no more digits in input.
how to put it together.
Learn C programming language. Write a program that implements the algorithm.
As I understand, an integer value has to be converted to another integer. From there it's just basic arithmetic, where the process generatally consists of:
Getting one digit from input.
Putting it in output.
Removing that digit from input.
shifting input & output to desired state
I came up with 3 separate such convert_* function implementations. First one is similar to common simple int->string conversion algorithms - it first converts the digits and that the results is "inverted". The second one extract the digits from propor position from input - getting the most significant base10 digit from input and moving between base10 digits of input. The third one, puts base10 digits on the end of hex number (startign from the mast significant base16 digit), and then shifts hex number to the right to handle 0x55000000 trailing zeros in result.
#include <limits.h>
#include <stdio.h>
const unsigned maxhexdigits = sizeof(unsigned) * CHAR_BIT / 4;
unsigned convert_andrevert(unsigned n) {
unsigned o = 0;
unsigned hexdigits = 0;
// Convert hex digits from "the back"
while (n && hexdigits != maxhexdigits) {
o <<= 4;
o += n % 10;
n /= 10;
++hexdigits;
}
const unsigned swaps = hexdigits / 2;
//printf("a %#x %d %d \n", o, hexdigits, swaps);
// Invert hex digits
for (unsigned i = 0; i < swaps; ++i) {
const unsigned m1 = 0xFu << (i * 4);
const unsigned m2 = 0xFu << ((hexdigits - i - 1) * 4);
const unsigned road = (hexdigits - i * 2 - 1) * 4;
// extract bits m1
unsigned t = (o & m1) << road;
//printf("b o=%#x i=%#x 1=%#x m2=%#x t=%#x road=%d\n", o, i, m1, m2, t, road);
// set bit m1 in place of m2
o = (o & ~m1) | ((o & m2) >> road);
// set bit m2 in place of m1
o = (o & ~m2) | t;
}
return o;
}
unsigned mypow10u(unsigned i) {
unsigned r = 1;
while (i--) {
r *= 10;
}
return r;
}
unsigned convert_frommax(unsigned n) {
n %= mypow10u(maxhexdigits);
unsigned o = 0;
// always start from the maximuim digit, because
// we know it's location.
for (int i = maxhexdigits - 1; i >= 0; --i) {
o <<= 4;
//printf("o=%#x u=%d pow10u(i)=%u digit=%u rest=%u\n",
//o, i, mypow10u(i),
//n / mypow10u(i),
//n % mypow10u(i));
// extract leading base10 digit
o += n / mypow10u(i);
n %= mypow10u(i);
}
return o;
}
unsigned convert_andshift(unsigned n) {
unsigned o = 0;
unsigned hexdigits = 0;
// Convert hex digits from "the back"
// put put them from the front.
while (n && hexdigits != maxhexdigits) {
o >>= 4;
o += (n % 10) << (maxhexdigits * 4 - 4);
//printf("o=%#x %d\n", o, n%10);
n /= 10;
++hexdigits;
}
// Shift right to handle leading (trailing?) zeros.
o >>= ((maxhexdigits - hexdigits) * 4);
return o;
}
void testin(unsigned r, unsigned rr) {
printf(" -> %#x %s", rr, r == rr ? "OK" : "FAIL");
}
void TEST(unsigned a, unsigned r) {
printf("%u", a);
testin(r, convert_andrevert(a));
testin(r, convert_frommax(a));
testin(r, convert_andshift(a));
printf("\n");
}
int main() {
TEST(1, 0x1);
TEST(55, 0x55);
TEST(123, 0x123);
TEST(2021, 0x2021);
TEST(12345678, 0x12345678);
}
From basic profiling, convert_andshift is the fastest function.
Here is an approach:
#include<stdio.h>
int main()
{
int num = 0;
char cNumHex[20];
puts("Enter a decimal formed hex number: ");
scanf("%d",&num);
sprintf(cNumHex, "0x%d", num);
printf("\nThe entered as hex: %s\n", cNumHex);
return 0;
}
The output:
Enter a decimal formed hex number:
49478
The entered as hex: 0x49478

Obtaining a sequence of bits from a C-style string in C?

I need to obtain a sequence of bits from a char* fixed length C-style string in C, how can I do it? I need a sequence of bits representing the string, not a particular one. I need to do it strictly in C not in C++.
You can use a simple bitmask of only one 1 and scan through the string one byte at a time, starting with mask = 0x80 (binary 10000000) and going down to 1 (binary 00000001).
#include <stdio.h>
#define N 5
int main(void) {
char mystring[N] = "abcd";
unsigned i;
unsigned char mask;
for (i = 0; i < N; i++) {
unsigned char c = mystring[i];
unsigned char mask = 0x80;
do {
putchar(c & mask ? '1' : '0');
mask >>= 1;
} while (mask > 0);
putchar(' ');
}
putchar('\n');
return 0;
}
Result:
01100001 01100010 01100011 01100100 00000000

Error in Program to implement cyclic redundancy check

I have tried to implement crc in c.My logic is not very good.What I have tried is to copy the message(msg) in a temp variable and at the end I have appended number of zeros 1 less than the number of bits in crc's divisor div.
for ex:
msg=11010011101100
div=1011
then temp becomes:
temp=11010011101100000
div= 10110000000000000
finding xor of temp and div and storing it in temp
gives temp=01100011101100000 counting number of zeros appearing before the first '1' of temp and shifting the characters of div right to that number and then repeating the same process until decimal value of temp becomes less than decimal value of div. Which gives the remainder.
My problem is when I append zeros at the end of temp it stores 0's along with some special characters like this:
temp=11010011101100000$#UFI#->Jp#|
and when I debugged I got error
Floating point:Stack Underflow
here is my code:
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<string.h>
void main() {
char msg[100],div[100],temp[100];
int i,j=0,k=0,l=0,msglen,divlen,newdivlen,ct=0,divdec=0,tempdec=0;
printf("Enter the message\n");
gets(msg);
printf("\nEnter the divisor\n");
gets(div);
msglen=strlen(msg);
divlen=strlen(div);
newdivlen=msglen+divlen-1;
strcpy(temp,msg);
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
printf("\nModified Temp:");
printf("%s",temp);
for(i=divlen;i<newdivlen;i++)
div[i]='0';
printf("\nModified div:");
printf("%s",div);
for(i=newdivlen;i>0;i--)
divdec=divdec+div[i]*pow(2,j++);
for(i=newdivlen;i>0;i--)
tempdec=tempdec+temp[i]*pow(2,k++);
while(tempdec>divdec)
{
for(i=0;i<newdivlen;i++)
{
temp[i]=(temp[i]==div[i])?'0':'1';
while(temp[i]!='1')
ct++;
}
for(i=newdivlen+ct;i>ct;i--)
div[i]=div[i-ct];
for(i=0;i<ct;i++)
div[i]='0';
tempdec=0;
for(i=newdivlen;i>0;i--)
tempdec=tempdec+temp[i]*pow(2,l++);
}
printf("%s",temp);
getch();
}
and this part of the code :
for(i=newdivlen;i>0;i--)
divdec=divdec+div[i]*pow(2,i);
gives error Floating Point:Stack Underflow
The problem is that you wrote a 0 over the NUL terminator, and didn't put another NUL terminator on the string. So printf gets confused and prints garbage. Which is to say that this code
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
printf("\nModified Temp:");
printf("%s",temp);
should be
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
temp[i] = '\0'; // <--- NUL terminate the string
printf("\nModified Temp:");
printf("%s",temp);
You have to do this with integers
int CRC(unsigned int n);
int CRC_fast(unsigned int n);
void printbinary(unsigned int n);
unsigned int msb(register unsigned int n);
int main()
{
char buf[5];
strcpy(buf, "ABCD");
//convert string to number,
//this is like 1234 = 1*1000 + 2*100 + 3*10 + 4, but with hexadecimal
unsigned int n = buf[3] * 0x1000000 + buf[2] * 0x10000 + buf[1] * 0x100 + buf[3];
/*
- "ABCD" becomes just a number
- Any string of text can become a sequence of numbers
- you can work directly with numbers and bits
- shift the bits left and right using '<<' and '>>' operator
- use bitwise operators & | ^
- use basic math with numbers
*/
//finding CRC, from Wikipedia example:
n = 13548; // 11010011101100 in binary (14 bits long), 13548 in decimal
//padding by 3 bits: left shift by 3 bits:
n <<= 3; //11010011101100000 (now it's 17 bits long)
//17 is "sort of" the length of integer, can be obtained from 1 + most significant bit of n
int m = msb(n) + 1;
printf("len(%d) = %d\n", n, m);
int divisor = 11; //1011 in binary (4 bits)
divisor <<= (17 - 4);
//lets see the bits:
printbinary(n);
printbinary(divisor);
unsigned int result = n ^ divisor;// XOR operator
printbinary(result);
//put this in function:
n = CRC(13548);
n = CRC_fast(13548);
return 0;
}
void printbinary(unsigned int n)
{
char buf[33];
memset(buf, 0, 33);
unsigned int mask = 1 << 31;
//result in binary: 1 followed by 31 zero
for (int i = 0; i < 32; i++)
{
buf[i] = (n & mask) ? '1' : '0';
//shift the mask by 1 bit to the right
mask >>= 1;
/*
mask will be shifted like this:
100000... first
010000... second
001000... third
*/
}
printf("%s\n", buf);
}
//find most significant bit
unsigned int msb(register unsigned int n)
{
unsigned i = 0;
while (n >>= 1)
i++;
return i;
}
int CRC(unsigned int n)
{
printf("\nCRC(%d)\n", n);
unsigned int polynomial = 11;
unsigned int plen = msb(polynomial);
unsigned int divisor;
n <<= 3;
for (;;)
{
int shift = msb(n) - plen;
if (shift < 0) break;
divisor = polynomial << shift;
printbinary(n);
printbinary(divisor);
printf("-------------------------------\n");
n ^= divisor;
printbinary(n);
printf("\n");
}
printf("result: %d\n\n", n);
return n;
}
int CRC_fast(unsigned int n)
{
printf("\nCRC_fast(%d)\n", n);
unsigned int polynomial = 11;
unsigned int plen = msb(polynomial);
unsigned int divisor;
n <<= 3;
for (;;)
{
int shift = msb(n) - plen;
if (shift < 0) break;
n ^= (polynomial << shift);
}
printf("result: %d\n\n", n);
return n;
}
Previous problems with string method:
This is infinite loop:
while (temp[i] != '1')
{
ct++;
}
Previous problems with string method:
This one is too confusing:
for (i = newdivlen + ct; i > ct; i--)
div[i] = div[i - ct];
I don't know what ct is. The for loops are all going backward, this makes the code faster sometimes (maybe 1 nanosecond faster), but it makes it very confusing.
There is another while loop,
while (tempdec > divdec)
{
//...
}
This may go on forever if you don't get the expected result. It makes it very hard to debug the code.

How to get certain bits of a char array to another char array in C?

I have a char (input) array with size 60. I want to write a function that returns certain bits of the input array.
char input_ar[60];
char output_ar[60];
void func(int bits_starting_number, int total_number_bits){
}
int main()
{
input_ar[0]=0b11110001;
input_ar[1]=0b00110011;
func(3,11);
//want output_ar[0]=0b11000100; //least significant 6 bits of input_ar[0] and most significant bits (7.8.) of input_ar[1]
//want output_ar[1]=0b00000110; //6.5.4. bits of input_ar[1] corresponds to 3 2 1. bits of output_ar[1] (110) right-aligned other bits are 0, namely 8 7 ...4 bits is zero
}
I want to ask what's the termiology of this algorithm? How can I easily write the code? Any clues appricated.
Note: I use XC8, arrray of bits are not allowed.
This answer makes the following assumptions. Bits are numbered from 1, the first bit is the MS bit of the first byte. The extracted bit array must be left-aligned. Unused bits on the right are padded with 0.
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define MAX_LEN 60
#define BMASK (1 << (CHAR_BIT-1))
unsigned char input_ar[MAX_LEN];
unsigned char output_ar[MAX_LEN];
int func(int bits_starting_number, int total_number_bits) {
// return the number of bits copied
int sors_ind, sors_bit, dest_ind = 0;
int i, imask, omask;
memset (output_ar, 0, MAX_LEN); // clear the result
if (bits_starting_number < 1 || bits_starting_number > MAX_LEN * CHAR_BIT)
return 0; // bit number is out of range
if (total_number_bits < 1)
return 0; // nothing to do
bits_starting_number--;
if (bits_starting_number + total_number_bits > MAX_LEN * CHAR_BIT)
total_number_bits = MAX_LEN * CHAR_BIT - bits_starting_number;
sors_ind = bits_starting_number / CHAR_BIT;
sors_bit = CHAR_BIT - 1 - (bits_starting_number % CHAR_BIT);
imask = 1 << sors_bit;
omask = BMASK;
for (i=0; i<total_number_bits; i++) {
if (input_ar[sors_ind] & imask)
output_ar[dest_ind] |= omask; // copy a 1 bit
if ((imask >>= 1) == 0) { // shift the input mask
imask = BMASK;
sors_ind++; // next input byte
}
if ((omask >>= 1) == 0) { // shift the output mask
omask = BMASK;
dest_ind++; // next output byte
}
}
return total_number_bits;
}
void printb (int value) {
int i;
for (i=BMASK; i; i>>=1) {
if (value & i)
printf("1");
else
printf("0");
}
printf (" ");
}
int main(void) {
int i;
input_ar[0]= 0xF1; // 0b11110001
input_ar[1]= 0x33; // 0b00110011
printf ("Input: ");
for (i=0; i<4; i++)
printb(input_ar[i]);
printf ("\n");
func(3,11);
printf ("Output: ");
for (i=0; i<4; i++)
printb(output_ar[i]);
printf ("\n");
return 0;
}
Program output
Input: 11110001 00110011 00000000 00000000
Output: 11000100 11000000 00000000 00000000
First of all, the returntype: You can return a boolean array of length total_number_bits.
Inside your function you can do a forloop, starting at bits_starting_number, iterating total_number_bits times. For each number you can divide the forloopindex by 8 (to get the right char) and than bitshift a 1 by the forloopindex modulo 8 to get the right bit. Put it on the right spot in the output array (forloopindex - bits_starting_number) and you are good to go
This would become something like:
for(i = bits_starting_number; i < bits_starting_number + total_number_bits; i++) {
boolarr[i - bits_starting_number] = charray[i/8] & (1 << (i % 8));
}

Convert integer from (pure) binary to BCD

I'm to stupid right now to solve this problem...
I get a BCD number (every digit is an own 4Bit representation)
For example, what I want:
Input: 202 (hex) == 514 (dec)
Output: BCD 0x415
Input: 0x202
Bit-representation: 0010 0000 0010 = 514
What have I tried:
unsigned int uiValue = 0x202;
unsigned int uiResult = 0;
unsigned int uiMultiplier = 1;
unsigned int uiDigit = 0;
// get the dec bcd value
while ( uiValue > 0 )
{
uiDigit= uiValue & 0x0F;
uiValue >>= 4;
uiResult += uiMultiplier * uiDigit;
uiMultiplier *= 10;
}
But I know that's very wrong this would be 202 in Bit representation and then split into 5 nibbles and then represented as decimal number again
I can solve the problem on paper but I just cant get it in a simple C-Code
You got it the wrong way round. Your code is converting from BCD to binary, just as your question's (original) title says. But the input and output values you provided are correct only if you convert from binary to BCD. In that case, try:
#include <stdio.h>
int main(void) {
int binaryInput = 0x202;
int bcdResult = 0;
int shift = 0;
printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );
while (binaryInput > 0) {
bcdResult |= (binaryInput % 10) << (shift++ << 2);
binaryInput /= 10;
}
printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
return 0;
}
Proof: http://ideone.com/R0reQh
Try the following.
unsigned long toPackedBcd (unsigned int val)
{
unsigned long bcdresult = 0; char i;
for (i = 0; val; i++)
{
((char*)&bcdresult)[i / 2] |= i & 1 ? (val % 10) << 4 : (val % 10) & 0xf;
val /= 10;
}
return bcdresult;
}
Also one may try the following variant (although maybe little inefficient)
/*
Copyright (c) 2016 enthusiasticgeek<enthusiasticgeek#gmail.com> Binary to Packed BCD
This code may be used (including commercial products) without warranties of any kind (use at your own risk)
as long as this copyright notice is retained.
Author, under no circumstances, shall not be responsible for any code crashes or bugs.
Exception to copyright code: 'reverse string function' which is taken from http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
Double Dabble Algorithm for unsigned int explanation
255(binary) - base 10 -> 597(packed BCD) - base 16
H| T| U| (Keep shifting left)
11111111
1 1111111
11 111111
111 11111
1010 11111 <-----added 3 in unit's place (7+3 = 10)
1 0101 1111
1 1000 1111 <-----added 3 in unit's place (5+3 = 8)
11 0001 111
110 0011 11
1001 0011 11 <-----added 3 in ten's place (6+3 = 9)
1 0010 0111 1
1 0010 1010 1 <-----added 3 in unit's place (7+3 = 10)
10 0101 0101 -> binary 597 but bcd 255
^ ^ ^
| | |
2 5 5
*/
#include <stdio.h>
#include <string.h>
//Function Prototypes
unsigned int binaryToPackedBCD (unsigned int binary);
char * printPackedBCD(unsigned int bcd, char * bcd_string);
// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str);
//Function Definitions
unsigned int binaryToPackedBCD (unsigned int binary) {
const unsigned int TOTAL_BITS = 32;
/*Place holder for bcd*/
unsigned int bcd = 0;
/*counters*/
unsigned int i,j = 0;
for (i=0; i<TOTAL_BITS; i++) {
/*
Identify the bit to append to LSB of 8 byte or 32 bit word -
First bitwise AND mask with 1.
Then shift to appropriate (nth shift) place.
Then shift the result back to the lsb position.
*/
unsigned int binary_bit_to_lsb = (1<<(TOTAL_BITS-1-i)&binary)>>(TOTAL_BITS-1-i);
/*shift by 1 place and append bit to lsb*/
bcd = ( bcd<<1 ) | binary_bit_to_lsb;
/*printf("=> %u\n",bcd);*/
/*Don't add 3 for last bit shift i.e. in this case 32nd bit*/
if( i >= TOTAL_BITS-1) {
break;
}
/*else continue*/
/* Now, check every nibble from LSB to MSB and if greater than or equal 5 - add 3 if so */
for (j=0; j<TOTAL_BITS; j+=4) {
unsigned int temp = (bcd & (0xf<<j))>>j;
if(temp >= 0x5) {
/*printf("[%u,%u], %u, bcd = %u\n",i,j, temp, bcd);*/
/*Now, add 3 at the appropriate nibble*/
bcd = bcd + (3<<j);
// printf("Now bcd = %u\n", bcd);
}
}
}
/*printf("The number is %u\n",bcd);*/
return bcd;
}
char * printPackedBCD(unsigned int bcd, char * bcd_string) {
const unsigned int TOTAL_BITS = 32;
printf("[LSB] =>\n");
/* Now, check every nibble from LSB to MSB and convert to char* */
for (unsigned int j=0; j<TOTAL_BITS; j+=4) {
//for (unsigned int j=TOTAL_BITS-1; j>=4; j-=4) {
unsigned int temp = (bcd & (0xf<<j))>>j;
if(temp==0){
bcd_string[j/4] = '0';
} else if(temp==1){
bcd_string[j/4] = '1';
} else if(temp==2){
bcd_string[j/4] = '2';
} else if(temp==3){
bcd_string[j/4] = '3';
} else if(temp==4){
bcd_string[j/4] = '4';
} else if(temp==5){
bcd_string[j/4] = '5';
} else if(temp==6){
bcd_string[j/4] = '6';
} else if(temp==7){
bcd_string[j/4] = '7';
} else if(temp==8){
bcd_string[j/4] = '8';
} else if(temp==9){
bcd_string[j/4] = '9';
} else {
bcd_string[j/4] = 'X';
}
printf ("[%u - nibble] => %c\n", j/4, bcd_string[j/4]);
}
printf("<= [MSB]\n");
reverse(bcd_string);
return bcd_string;
}
// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str)
{
if (str != 0 && *str != '\0') // Non-null pointer; non-empty string
{
char *end = str + strlen(str) - 1;
while (str < end)
{
char tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}
int main(int argc, char * argv[])
{
unsigned int number = 255;
unsigned int bcd = binaryToPackedBCD(number);
char bcd_string[8];
printPackedBCD(bcd, bcd_string);
printf("Binary (Base 10) = %u => Packed BCD (Base 16) = %u\n OR \nPacked BCD String = %s\n", number, bcd, bcd_string);
return 0;
}
The real problem here is confusion of bases and units
The 202 should be HEX which equates to 514 decimal... and therefore the BCD calcs are correct
Binary code decimal will convert the decimal (514) into three nibble sized fields:
- 5 = 0101
- 1 = 0001
- 4 = 0100
The bigger problem was that you have the title the wrong way around, and you are converting Uint to BCD, whereas the title asked for BCD to Unint
My 2 cents, I needed similar for a RTC chip which used BCD to encode the time and date info. Came up with the following macros that worked fine for the requirement:
#define MACRO_BCD_TO_HEX(x) ((BYTE) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F)))
#define MACRO_HEX_TO_BCD(x) ((BYTE) (((x / 10 ) << 4) | ((x % 10))))
A naive but simple solution:
char buffer[16];
sprintf(buffer, "%d", var);
sscanf(buffer, "%x", &var);
This is the solution that I developed and works great for embedded systems, like Microchip PIC microcontrollers:
#include <stdio.h>
void main(){
unsigned int output = 0;
unsigned int input;
signed char a;
//enter any number from 0 to 9999 here:
input = 1265;
for(a = 13; a >= 0; a--){
if((output & 0xF) >= 5)
output += 3;
if(((output & 0xF0) >> 4) >= 5)
output += (3 << 4);
if(((output & 0xF00) >> 8) >= 5)
output += (3 << 8);
output = (output << 1) | ((input >> a) & 1);
}
printf("Input decimal or binary: %d\nOutput BCD: %X\nOutput decimal: %u\n", input, output, output);
}
This is my version for a n byte conversion:
//----------------------------------------------
// This function converts n bytes Binary (up to 8, but can be any size)
// value to n bytes BCD value or more.
//----------------------------------------------
void bin2bcdn(void * val, unsigned int8 cnt)
{
unsigned int8 sz, y, buff[20]; // buff = malloc((cnt+1)*2);
if(cnt > 8) sz = 64; // 8x8
else sz = cnt * 8 ; // Size in bits of the data we shift
memset(&buff , 0, sizeof(buff)); // Clears buffer
memcpy(&buff, val, cnt); // Copy the data to buffer
while(sz && !(buff[cnt-1] & 0x80)) // Do not waste time with null bytes,
{ // so search for first significative bit
rotate_left(&buff, sizeof(buff)); // Rotate until we find some data
sz--; // Done this one
}
while(sz--) // Anyting left?
{
for( y = 0; y < cnt+2; y++) // Here we fix the nibbles
{
if(((buff[cnt+y] + 0x03) & 0x08) != 0) buff[cnt+y] += 0x03;
if(((buff[cnt+y] + 0x30) & 0x80) != 0) buff[cnt+y] += 0x30;
}
rotate_left(&buff, sizeof(buff)); // Rotate the stuff
}
memcpy(val, &buff[cnt], cnt); // Copy the buffer to the data
// free(buff); //in case used malloc
} // :D Done
long bin2BCD(long binary) { // double dabble: 8 decimal digits in 32 bits BCD
if (!binary) return 0;
long bit = 0x4000000; // 99999999 max binary
while (!(binary & bit)) bit >>= 1; // skip to MSB
long bcd = 0;
long carry = 0;
while (1) {
bcd <<= 1;
bcd += carry; // carry 6s to next BCD digits (10 + 6 = 0x10 = LSB of next BCD digit)
if (bit & binary) bcd |= 1;
if (!(bit >>= 1)) return bcd;
carry = ((bcd + 0x33333333) & 0x88888888) >> 1; // carrys: 8s -> 4s
carry += carry >> 1; // carrys 6s
}
}
Simple solution
#include <stdio.h>
int main(void) {
int binaryInput = 514 ; //0x202
int bcdResult = 0;
int digit = 0;
int i=1;
printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );
while (binaryInput > 0) {
digit = binaryInput %10; //pick digit
bcdResult = bcdResult+digit*i;
i=16*i;
binaryInput = binaryInput/ 10;
}
printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
return 0;
}
Binary: 0x202 (dec: 514)
BCD: 0x514 (dec: 1300)
You can also try the following:
In every iteration the remainder ( represented as a nibble ) is positioned in its corresponding place.
uint32_t bcd_converter(int num)
{
uint32_t temp=0;
int i=0;
while(num>0){
temp|=((num%10)<<i);
i+=4;
num/=10;
}
return temp;
}

Resources