How to convert a char into an unsigned int? - c

How the program works
./my program 1 10000100 01000000001000001000000
// Reads the argv's
// Converts them into unsigned ints
How do I convert the char* into an unsigned int? I assume I use bit manipulation, but I am a little lost on the conversion of a char to an unsigned int.
The code.
struct _float {
unsigned int sign:1, exp:8, frac:23;
};
union _bits32 {
float fval; // Bits as a float
Word xval; // Bits as a word
Float32 bits; // manipulate individual bits
};
union _bits32 getBits(char *sign, char *exp, char *frac);
int main(int argc, char **argv) {
u = getBits(argv[1], argv[2], argv[3]);
return 0;
}
// Here I am converting the char's into unsigned ints
union _bits32 getBits(char *sign, char *exp, char *frac) {
Union32 new;
// convert char *sign into a single bit in new.bits
new.bits.sign = *sign;
// convert char *exp into an 8-bit value in new.bits
new.bits.exp = *exp;
// convert char *frac into a 23-bit value in new.bits
new.bits.frac = *frac;
return new;
}

So, you need to read each bit (1 character per bit) and save that to an integer in the correct bit positions. Here is a function that would do so for an arbitrary length up to 32 bits.
// Takes in the string with the bits (e.g. "01010100011")
// Returns the integer represented by those bits (leading bits are 0's)
int parseFromBinary(char* bitString) {
int val = 0;
int i = 0;
// While there are more characters
while (bitString[i] != 0) {
// Shift everything left (multiply by 2) to make room for the new bit
val <<= 1;
// Add the new bit (no effect if it is a 0)
val |= bitString[i] - '0';
i++;
}
return val;
}
You would want to call this function once for each field, though it really isn't necessary to loop over the 1 sign bit, and that would arguably make things less clear.

#include <stdio.h>
int main ( int argc, char *argv[])
{
unsigned int ra,rb;
if(argc<2) return(1);
rb=0;
for(ra=0;argv[1][ra];ra++)
{
rb<<=1;
rb|=argv[1][ra]&1;
}
printf("0x%08X\n",rb);
return(0);
}
build and run
gcc so.c -o so
./so 000100000
0x00000020
./so 101010101
0x00000155
./so 010101010
0x000000AA
./so 101
0x00000005
the string "101" looks like this when run:
argv[1]={0x31,0x30,0x31};
because it is ASCII. (google ASCII chart and go to images)
The desired result is the value 0b101 which is 0x5 or decimal 5.
Generally you want to parse through that string
argv[1][0]=0x31;
argv[1][1]=0x30;
argv[1][2]=0x31;
argv[1][3]=0x00;
starting with the first byte in the string 0x31 need to extract the lsbit and save it. This is the 0b1xx bit of our final number which we can see as humans but need to get the program to do it. When on to the next byte if you shift your accumulator left one and make room for the next bit you will end up with 0b10 and orr in a zero ending up with 0b10 which is these two bits of our final answer 0b10x
now shift the 0b10 left one to make room for the next bit, take that bit from the ascii byte resulting in 0b101. You can repeat this as long as you have room in the variable.
Because the string order left to right is array item 0,1,2,3. And these line up with the msbit to lsbit in that order of the binary value we want to extract the first byte in the array is our msbit, so if we keep shifting that left as we add in more bits our msbit ends up on the left as desired and the last bit we add, the last byte in the string, and that will be the lsbit when done.
EDIT
#include <stdio.h>
int main ( int argc, char *argv[])
{
unsigned int ra,rb;
if(argc<2) return(1);
rb=0;
for(ra=0;argv[1][ra];ra++)
{
rb<<=1;
rb|=argv[1][ra]&1;
}
//printf("0x%08X\n",rb);
printf("0b");
for(ra=0x80000000;ra;ra>>=1)
{
if(ra&rb) printf("1"); else printf("0");
}
printf("\n");
return(0);
}
gives
./so 101
0b00000000000000000000000000000101
./so 101010101
0b00000000000000000000000101010101
./so 111000111000
0b00000000000000000000111000111000
EDIT2
You really have to understand binary, ASCII, visual representations, bit manipulation, etc.
#include <stdio.h>
int main ( int argc, char *argv[])
{
unsigned int ra,rb;
if(argc<2) return(1);
rb=0;
for(ra=0;argv[1][ra];ra++)
{
rb<<=1;
rb|=argv[1][ra]&1;
}
printf("hex %08X\n",rb);
printf("octal %011o\n",rb);
printf("binary ");
for(ra=0x80000000;ra;ra>>=1)
{
if(ra&rb) printf("1"); else printf("0");
}
printf("\n");
return(0);
}
gives
./so 101010101
hex 00000155
octal 00000000525
binary 00000000000000000000000101010101
./so 111000111
hex 000001C7
octal 00000000707
binary 00000000000000000000000111000111
./so 101
hex 00000005
octal 00000000005
binary 00000000000000000000000000000101
these binary bits
000111000111
to make them easier to read and communicate can be broken into octal:
000 111 000 111
start from the right and take three at a time, this gives 0707
Or hex, start from the right take them four at a time
0001 1100 0111
this gives 1C7
But in order to "see" them the computer went back to ASCII (and this day and age that was converted into a bigger representation that includes language differences)
I manually turned the binary number 0101 into 0x31,0x30,0x31 so we could see "101". The formatted printf, 0101 became 0x35 so we could see "5", likewise the binary number 0101, became 0x30,0x35 so we could see "05".
EDIT3
#include <stdio.h>
int main ( int argc, char *argv[])
{
unsigned int ra,rb;
if(argc<2) return(1);
rb=0;
for(ra=0;argv[1][ra];ra++)
{
rb<<=1;
rb|=argv[1][ra]&1;
}
printf("binary (base 2) ");
for(ra=0x80000000;ra;ra>>=1)
{
char rc;
if(ra&rb) rc=0x31; else rc=0x30;
printf("%c",rc);
}
printf("\n");
printf("base four ");
for(ra=30;;ra-=2)
{
char rc;
rc=(rb>>ra)&3;
rc+=0x30;
printf("%c",rc);
if(ra==0) break;
}
printf("\n");
printf("octal (base 8) ");
for(ra=30;;ra-=3)
{
char rc;
rc=(rb>>ra)&7;
rc+=0x30;
printf("%c",rc);
if(ra==0) break;
}
printf("\n");
printf("hexadecimal (base 16) ");
for(ra=28;;ra-=4)
{
char rc;
rc=(rb>>ra)&0xF;
rc+=0x30;
if(rc>0x39) rc+=7;
printf("%c",rc);
if(ra==0) break;
}
printf("\n");
return(0);
}
./so 101
binary (base 2) 00000000000000000000000000000101
base four 0000000000000011
octal (base 8) 00000000005
hexadecimal (base 16) 00000005
./so 1010
binary (base 2) 00000000000000000000000000001010
base four 0000000000000022
octal (base 8) 00000000012
hexadecimal (base 16) 0000000A
./so 11001100
binary (base 2) 00000000000000000000000011001100
base four 0000000000003030
octal (base 8) 00000000314
hexadecimal (base 16) 000000CC
./so 111000111
binary (base 2) 00000000000000000000000111000111
base four 0000000000013013
octal (base 8) 00000000707
hexadecimal (base 16) 000001C7
./so 111100001111
binary (base 2) 00000000000000000000111100001111
base four 0000000000330033
octal (base 8) 00000007417
hexadecimal (base 16) 00000F0F
EDIT
#include <stdio.h>
int main ( void )
{
unsigned int ra;
unsigned int rb;
unsigned int rc;
char s[32];
rb=0x1234;
for(ra=0x8000;ra;ra>>=1)
{
printf("0x%04X & 0x%04X = 0x%04X ",ra,rb,ra&rb);
if(ra&rb) printf("1"); else printf("0");
printf("\n");
}
for(ra=0x8000;ra;ra>>=1)
{
if(ra&rb) printf("1"); else printf("0");
}
printf("\n");
for(ra=0;ra<16;ra++)
{
if((ra&3)==0) printf(" ");
if((rb>>(15-ra))&1) printf("1"); else printf("0");
}
printf("\n");
for(rc=0,ra=0x8000;ra;ra>>=1,rc++)
{
if(ra&rb) s[rc]='1'; else s[rc]='0';
}
s[rc++]='\r';
s[rc++]='\n';
s[rc]=0;
for(ra=0;s[ra];ra++)
{
printf("0x%02X ",s[ra]);
}
printf("\n");
printf("%s",s);
return(0);
}
output
0x8000 & 0x1234 = 0x0000 0
0x4000 & 0x1234 = 0x0000 0
0x2000 & 0x1234 = 0x0000 0
0x1000 & 0x1234 = 0x1000 1
0x0800 & 0x1234 = 0x0000 0
0x0400 & 0x1234 = 0x0000 0
0x0200 & 0x1234 = 0x0200 1
0x0100 & 0x1234 = 0x0000 0
0x0080 & 0x1234 = 0x0000 0
0x0040 & 0x1234 = 0x0000 0
0x0020 & 0x1234 = 0x0020 1
0x0010 & 0x1234 = 0x0010 1
0x0008 & 0x1234 = 0x0000 0
0x0004 & 0x1234 = 0x0004 1
0x0002 & 0x1234 = 0x0000 0
0x0001 & 0x1234 = 0x0000 0
0001001000110100
0001 0010 0011 0100
0x30 0x30 0x30 0x31 0x30 0x30 0x31 0x30 0x30 0x30 0x31 0x31 0x30 0x31 0x30 0x30 0x0D 0x0A
0001001000110100

In addition to the other answers, the "confused" part most likely stems from the fact that getBits will store the value in new.bits with the bits reversed. Similar to host-to-network and network-to-host byte order, but completely bitwise reversed in your case.
Where you have
struct _float {
unsigned int sign:1, exp:8, frac:23;
};
You have a single bitfield where you designate sign as the most-significant bit. In memory, on a little-endian architecture this will be bit-0, not bit-31, resulting in your manipulation in getBits of new.bits leaving new.fval and new.xval being held in memory backwards.
Now, of course, the simple fix is to reverse your bitfield, e.g.
struct _float {
unsigned int frac:23, exp:8, sign:1;
};
To illustrate the point, let's just take new and reverse the bits before return. Nothing fancy, just a loop to reverse the bits of an unsigned value, e.g.
/* reverse the bits in v, sz number of bits */
unsigned revbits (unsigned v, int sz)
{
unsigned r = 0;
for (int i = 0; i < sz; i++)
r |= ((v >> i) & 0x1) << (sz - i - 1);
return r;
}
Also, note in getBits you cannot assign the strings to the bitfield values, you must OR and shift each individual bit into the proper location within the bitfield, while subtracting '0' to convert from ASCII to integer value, for instance:
/* convert char *exp into an 8-bit value in new.bits */
for (int i = 0; i < EXP; i++)
new.bits.exp |= (exp[i] - '0') << i;
Now lets reverse the bits of new in getBits before return, e.g.
/* convert three bit-strings (already checked)
* into the components of a struct _float
*/
Union32 getBits (char *sign, char *exp, char *frac) {
Union32 new = { .xval = 0 };
/* convert char *sign into a single bit in new.bits */
new.bits.sign = *sign - '0';
/* convert char *exp into an 8-bit value in new.bits */
for (int i = 0; i < EXP; i++)
new.bits.exp |= (exp[i] - '0') << i;
/* convert char *frac into a 23-bit value in new.bits */
for (int i = 0; i < FRAC; i++)
new.bits.frac |= (frac[i] - '0') << i;
/* reverse the bit order */
new.xval = revbits (new.xval, sizeof new.xval * CHAR_BIT);
return new;
}
Now your example correctly outputs -40.015869. If you put all the pieces together, and use constants in your code, instead of sprinkling magic numbers throughout, and using CHAR_BIT from limits.h to insure we have the correct number of bit for our type, and adding a missing typedef for Word to unsigned, you could do something similar to:
#include <stdio.h>
#include <limits.h>
/* constants for use in code (don't use magic numbers) */
enum { SIGN = 1, EXP = 8, FRAC = 23 };
typedef struct _float {
unsigned sign:SIGN,
exp :EXP,
frac:FRAC;
} Float32;
typedef unsigned Word; /* you need typedef for unsigned as Word */
union _bits32 {
float fval; /* Bits as a float */
Word xval; /* Bits as a word */
Float32 bits; /* manipulate individual bits (reverse order) */
};
typedef union _bits32 Union32;
/* reverse the bits in v, sz number of bits */
unsigned revbits (unsigned v, int sz)
{
unsigned r = 0;
for (int i = 0; i < sz; i++)
r |= ((v >> i) & 0x1) << (sz - i - 1);
return r;
}
/* convert three bit-strings (already checked)
* into the components of a struct _float
*/
Union32 getBits (char *sign, char *exp, char *frac) {
Union32 new = { .xval = 0 };
/* convert char *sign into a single bit in new.bits */
new.bits.sign = *sign - '0';
/* convert char *exp into an 8-bit value in new.bits */
for (int i = 0; i < EXP; i++)
new.bits.exp |= (exp[i] - '0') << i;
/* convert char *frac into a 23-bit value in new.bits */
for (int i = 0; i < FRAC; i++)
new.bits.frac |= (frac[i] - '0') << i;
/* reverse the bit order */
new.xval = revbits (new.xval, sizeof new.xval * CHAR_BIT);
return new;
}
int main (int argc, char **argv) {
union _bits32 u = { .xval = 0 };
/* set u (default value is PI to 3.14159) */
u = getBits (argc > 1 ? argv[1] : "0",
argc > 2 ? argv[2] : "10000000",
argc > 3 ? argv[3] : "10010010000111111010000");
/* output fval */
printf ("u.fval %f\n", u.fval);
return 0;
}
Example Use/Output
Default case with PI:
$ ./bin/floatbits
u.fval 3.141590
Using your input:
$ ./bin/floatbits 1 10000100 01000000001000001000000
u.fval -40.015869
Rearranging the Order of Float32
As mentioned above, rather than reversing the bits before return in getBits, the more straight forward approach is to change the order of Float32 so that you have the bitfield order as FRAC, EXP, SIGN which would make the order in-memory of bits consistent with fval and xval.
Now you can simply fill each in getBit (while taking care to fill the bits in proper bit order for your host, e.g. little-endian, least significant bit is highest bit in range, etc.). This simply requires you recognizing that string[0] will map to bit[most-significant] for each of FRAC and EXP. With that change, the code would simplify to:
#include <stdio.h>
/* constants for use in code (don't use magic numbers) */
enum { SIGN = 1, EXP = 8, FRAC = 23 };
typedef struct _float {
unsigned frac:FRAC,
exp :EXP,
sign:SIGN;
} Float32;
typedef unsigned Word; /* you need typedef for unsigned as Word */
union _bits32 {
float fval; /* Bits as a float */
Word xval; /* Bits as a word */
Float32 bits; /* manipulate individual bits (reverse order) */
};
typedef union _bits32 Union32;
/* convert three bit-strings (already checked)
* into the components of a struct _float
*/
Union32 getBits (char *sign, char *exp, char *frac) {
Union32 new = { .xval = 0 };
/* convert char *sign into a single bit in new.bits */
new.bits.sign = *sign - '0';
/* convert char *exp into an 8-bit value in new.bits */
for (int i = 0; i < EXP; i++)
new.bits.exp |= (exp[EXP - i - 1] - '0') << i;
/* convert char *frac into a 23-bit value in new.bits */
for (int i = 0; i < FRAC; i++)
new.bits.frac |= (frac[FRAC - i - 1] - '0') << i;
return new;
}
int main (int argc, char **argv) {
union _bits32 u = { .xval = 0 };
/* set u (default value is PI to 3.14159) */
u = getBits (argc > 1 ? argv[1] : "0",
argc > 2 ? argv[2] : "10000000",
argc > 3 ? argv[3] : "10010010000111111010000");
/* output fval */
printf ("u.fval %f\n", u.fval);
return 0;
}
(the use/output is the same)
While bitfields are fine to learn, they are rarely portable. If your goal is portable code, then they are best avoided.
Let me know if you have questions.

#include <stdio.h>
int main () {
for (char ch = 'A'; ch <= 'Z'; ++ch) {
printf("%d\t", ch);
}
for (char ch = 'a'; ch <= 'z'; ++ch) {
printf("%d\t", ch);
}
return 0;
}

Related

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

Get rid of following binary numbers but keep bitsize

A bit new to C programming but I've made a binary mask in my program and there are following 0 on the wrong side.
Hex: 0x61
Binary Result: 0110000100000000
Binary Want: 0000000001100001
Is there a way I could shift them down to start from LSB instead?
Back of my mind is maybe, inverse the masking? Just a hunch.
Here's my function:
void printBin(char Key)
{
int count;
int bits = 16;
unsigned int mask = 1 << --bits;
for(count = 0; count <= bits; count++)
{
if( Key & mask)
{
printw("1");
}
else
{
printw("0");
}
Key <<= 1;
}
}
When you are trying to print a binary string, when you loop over your number shifting the bits as you are, you end up with the bits in reverse order. While you can simply print the binary representation, it is far easier to save binary representation to a character string (so you can save it in the correct order) and return a pointer to a statically declared string.
The 3 functions below (1) binstr returns a simple binary string containing only the number of bits that make up the representation; (2) binpad returns a binary string padded to sz bits (so you can print all 64-bits of a 64-bit number, including the leading zeros) and (3) binfmt that returns a string padded to sz bits in szs bit groups separated by sep character.
To use the functions, simply declare the constants that tell whether your computer is 32/64 bit, that will set the number of BITS_PER_LONG along with CHAR_BIT (generally 8). Their use is shown below in the example:
#include <stdio.h>
#include <stdlib.h>
/* CHAR_BIT */
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
/* BUILD_64 */
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
/* BITS_PER_LONG */
#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif
/* (note: adjust as required if not using x86/x86_64) */
char *binstr (unsigned long n);
char *binpad (unsigned long n, size_t sz);
char *binfmt (unsigned long n, unsigned char sz, unsigned char szs, char sep);
int main (int argc, char **argv) {
unsigned long v = argc > 1 ? strtoul (argv[1], NULL, 10) : 237;
unsigned long sz = argc > 2 ? strtoul (argv[2], NULL, 10) : sizeof v * CHAR_BIT;
unsigned long szs = argc > 3 ? strtoul (argv[3], NULL, 10) : CHAR_BIT;
/* print 16-bit binary representation */
printf ("\n binstr (%lu)\n %s\n", v, binstr (v));
printf ("\n binpad (%lu, %lu)\n %s\n", v, sz/4, binpad (v, sz/4));
printf ("\n binfmt (%lu, %lu, %hhu, %c)\n %s\n",
v, sz/4, (unsigned)szs/2, '-', binfmt (v, sz/4, szs/2, '-'));
/* print 32-bit binary representation */
printf ("\n binpad (%lu, %lu)\n %s\n", v, sz/2, binpad (v, sz/2));
printf ("\n binfmt (%lu, %lu, %hhu, %c)\n %s\n",
v, sz/2, (unsigned)szs, '-', binfmt (v, sz/2, szs, '-'));
/* print 64-bit binary representation */
printf ("\n binpad (%lu, %lu)\n %s\n", v, sz, binpad (v, sz));
printf ("\n binfmt (%lu, %lu, %hhu, %c)\n %s\n",
v, sz, (unsigned)szs, '-', binfmt (v, sz, szs, '-'));
return 0;
}
/** simple return of binary string */
char *binstr (unsigned long n)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
if (!n) {
*s = '0';
return s;
}
for (; n; n >>= 1)
*--p = (n & 1) ? '1' : '0';
return p;
}
/** returns pointer to binary representation of 'n' zero padded to 'sz'.
* returns pointer to string contianing binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits.
*/
char *binpad (unsigned long n, size_t sz)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
register size_t i;
for (i = 0; i < sz; i++)
*--p = (n>>i & 1) ? '1' : '0';
return p;
}
/** returns pointer to formatted binary representation of 'n' zero padded to 'sz'.
* returns pointer to string contianing formatted binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
* 'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
*/
char *binfmt (unsigned long n, unsigned char sz, unsigned char szs, char sep) {
static char s[BITS_PER_LONG * 2 + 1] = {0};
char *p = s + BITS_PER_LONG;
unsigned char i;
for (i = 0; i < sz; i++) {
p--;
if (i > 0 && szs > 0 && i % szs == 0)
*p-- = sep;
*p = (n >> i & 1) ? '1' : '0';
}
return p;
}
Output
$ ./bin/binstrtst
binstr (237)
11101101
binpad (237, 16)
0000000011101101
binfmt (237, 16, 4, -)
0000-0000-1110-1101
binpad (237, 32)
00000000000000000000000011101101
binfmt (237, 32, 8, -)
00000000-00000000-00000000-11101101
binpad (237, 64)
0000000000000000000000000000000000000000000000000000000011101101
binfmt (237, 64, 8, -)
00000000-00000000-00000000-00000000-00000000-00000000-00000000-11101101
Let me know if you have any questions. Hope this helps. You can test with your 0x61 (decimal 97), e.g.:
$ ./bin/binstrtst 97
binstr (97)
1100001
binpad (97, 16)
0000000001100001
binfmt (97, 16, 4, -)
0000-0000-0110-0001
binpad (97, 32)
00000000000000000000000001100001
binfmt (97, 32, 8, -)
00000000-00000000-00000000-01100001
binpad (97, 64)
0000000000000000000000000000000000000000000000000000000001100001
binfmt (97, 64, 8, -)
00000000-00000000-00000000-00000000-00000000-00000000-00000000-01100001
If you are always expecting only 8-bits, you could use right shift operator, something like this:
a = a >> 8;
this will shift the bits to its right by 8 bits.
You are applying a 16bit mask on an 8bit char. If you cast it to an int before you do your bit operations it will work as you expect it to.
void printBin(char key_8) // key_8: 0x01100001
{
int key_16 = key_8; // key_16: 0x0000000001100001
int count;
int bits = 16;
unsigned int mask = 1 << --bits; // mask: 0x1000000000000000
for(count = 0; count <= bits; count++)
{
if(key_16 & mask)
{
printw("1");
}
else
{
printw("0");
}
key_16 <<= 1;
}
}

Best Way to Simulate Logic Gates in C?

Hi I was wondering if anyone would be able to explain to me what is the best path to take if I wanted to simulate logic gates in a c program?
Lets say for example I create a program and use command line arguments
AND GATE
[console]% yourProgram 11001010 11110000
<console>% 11000000
If anyone could explain to me what the best route is to start with, I would greatly appreciate it. This is the code I have so far...
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] ) {
if( argc >= 3){
int result = atoi(argv[1])&&atoi(argv[2]);
printf("Input 1 is %d\n",atoi(argv[1]));
printf("Input 2 is %d\n",atoi(argv[2]));
printf("Result is %c\n",result);
}
return 0;
In addition to the comment suggesting basic corrections, if you want to make it a bit more useful and flexible, you could calculate the most significant bit and then use that to format a simple binary print routine to examine your bitwise operation.
The primary concepts are taking the input as a string of binary digits and converting them to a number with strtoul (base 2), and then following &'ing the inputs together to obtain result it is just a matter of computing how many bytes to print out and whether to format a single byte into nibbles or simply separate multiple bytes.
#include <stdio.h>
#include <stdlib.h>
/* BUILD_64 */
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
/* BITS_PER_LONG */
#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif
/* CHAR_BIT */
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
char *binstrfmt (unsigned long n, unsigned char sz, unsigned char szs, char sep);
static __always_inline unsigned long msbfls (unsigned long word);
int main (int argc, char **argv) {
if ( argc < 3) {
fprintf (stderr, "error: insufficient input. usage: %s b1 b1\n", argv[0]);
return 1;
}
/* input conversion and bitwise operation */
unsigned long b1 = strtoul (argv[1], NULL, 2);
unsigned long b2 = strtoul (argv[2], NULL, 2);
unsigned long result = b1 & b2;
/* variables to use to set binary print format */
unsigned char msb, msbmax, width, sepwidth;
msb = msbmax = width = sepwidth = 0;
/* find the greatest most significant bit */
msbmax = (msb = msbfls (b1)) > msbmax ? msb : msbmax;
msbmax = (msb = msbfls (b2)) > msbmax ? msb : msbmax;
msbmax = (msb = msbfls (result)) > msbmax ? msb : msbmax;
msbmax = msbmax ? msbmax : 1;
/* set the number of bytes to print and the separator width */
width = (msbmax / CHAR_BIT + 1) * CHAR_BIT;
sepwidth = width > CHAR_BIT ? CHAR_BIT : CHAR_BIT/2;
/* print the output */
printf("\n Input 1 : %s\n", binstrfmt (b1, width, sepwidth, '-'));
printf(" Input 2 : %s\n", binstrfmt (b2, width, sepwidth, '-'));
printf(" Result : %s\n\n", binstrfmt (result, width, sepwidth, '-'));
return 0;
}
/** returns pointer to formatted binary representation of 'n' zero padded to 'sz'.
* returns pointer to string contianing formatted binary representation of
* unsigned 64-bit (or less ) value zero padded to 'sz' digits with char
* 'sep' placed every 'szs' digits. (e.g. 10001010 -> 1000-1010).
*/
char *binstrfmt (unsigned long n, unsigned char sz, unsigned char szs, char sep) {
static char s[2 * BITS_PER_LONG + 1] = {0};
char *p = s + 2 * BITS_PER_LONG;
unsigned char i;
for (i = 0; i < sz; i++) {
p--;
if (i > 0 && szs > 0 && i % szs == 0)
*p-- = sep;
*p = (n >> i & 1) ? '1' : '0';
}
return p;
}
/* return the most significant bit (MSB) for the value supplied. */
static __always_inline unsigned long msbfls(unsigned long word)
{
if (!word) return 0;
int num = BITS_PER_LONG - 1;
#if BITS_PER_LONG == 64
if (!(word & (~0ul << 32))) {
num -= 32;
word <<= 32;
}
#endif
if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
num -= 16;
word <<= 16;
}
if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
num -= 8;
word <<= 8;
}
if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
num -= 4;
word <<= 4;
}
if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
num -= 2;
word <<= 2;
}
if (!(word & (~0ul << (BITS_PER_LONG-1))))
num -= 1;
return num;
}
Example Output
$ ./bin/andargs 11001010 11110000
Input 1 : 1100-1010
Input 2 : 1111-0000
Result : 1100-0000
$ ./bin/andargs 1100101011110000 1111000011001010
Input 1 : 11001010-11110000
Input 2 : 11110000-11001010
Result : 11000000-11000000
Use this code. (for AND operation):
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] ) {
if( argc >= 3){
int i=0;
printf("1st i/p = %s\n2nd i/p = %s\n",argv[1],argv[2]);
for (i=0; argv[1][i]!='\0'; i++){ //this assumes there are 2 inputs, of equal size, having bits(1,0) as its digits
argv[1][i] = argv[1][i] & argv[2][i]; //modifies argv[1] to your required answer
}
printf("Answer: %s\n",argv[1]);
}
return 0;
}

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