I'm trying to convert a BCD to ascii and vice versa and saw a solution similar to this while browsing, but don't fully understand it. Could someone explain it?
void BCD_Ascii(unsigned char src, char *dest) {
outputs = "0123456789"
*dest++ = outputs[src>>4];
*dest++ = outputs[src&0xf];
*dest = '\0';
}
Regarding your first question: Explaining the method:
You are right about src>>4, this shifts the character value 4 bits to the right which means it is returning the value of the higher hexdecimal digit.
e.g. if src is '\30' then src>>3 will evaluate to 3 or '\3'.
src&0xf is getting the lower hexdecimal digit by ANDing the src value with 0xF with is the binary value 1111 (not 11111111). e.g. if src is '\46' then src&0xf will evaluate to 6.
There are two important notes here while trying to understand the method:
First: The method cannot handle input when src has either the two digits above 9. i.e. if src was equal to '\3F' for instance, the method will overrun buffer.
Second: beware that this method adds the two digit characters at a certain location in a string and then terminates the string. The caller logic should be responsible for where the location is, incrementing the pointer, and making sure the output buffer allows three characters (at least) after the input pointer location.
Regarding your second question:
A reverse method could be as following:
unsigned char Ascii_BCD(const char* src) {
return (unsigned char)((src[0] - 0x30) * 0x10 + src[1] - 0x30);
}
[Edit: adding explanation to the reverse method]
The two ASCII digits at location 0 and 1 are subtracted of by 0x30 or '0' to convert from ascii to binary. E.g. the digit '4' is represented by the ascii code 0x34 so subtracting 0x30 will evaluate to 4.
Then the first digit which is the higher is multiplied by 0x10 to shift the value by 4 bits to the left.
The two values are added to compose the BCD value.
The opposite function can be:
BYTE ASC_BCD( char * asc )
{
return (BYTE)( ( asc[0] & 15 ) << 4 ) | ( asc[1] & 15 );
}
Char codes '0'..'9' can be converted to hex with & 15 or & 0x0F. Then make shift and | to combine.
The function converts a character in binary-coded decimal into a string.
First the upper 4 bits of src are obtained:
src>>4
The function then assumes the values those bits represent are in the range 0-9. Then that value is used to get an index in the string literal outputs:
outputs[src>>4];
The value is written into address which is pointed to by dest. This pointer is then incremented.
*dest++ = outputs[src>>4];
Then the lower 4 bits of src are used:
src&0xf
Again assuming the values of those bits, are representing a value in range 0-9. And the rest is the same as before:
*dest++ = outputs[src&0xf];
Finally a 0 is written into dest, to terminate it.
Related
so below is some code which I am using to understand how to get the binary of a double in C however there are some areas of the code which do not make sense to me and I have tried using print statements to help me but to no avail
#include <stdio.h>
#include <string.h>
#include <limits.h>
void double_to_bits(double val);
int main(void)
{
unsigned idx;
double vals[] = { 10 };
for (idx = 0; idx < 4; idx++ ) {
printf("\nvals[%u]= %+lf-->>", idx, vals[idx] );
double_to_bits(vals[idx] );
}
printf("\n");
return 0;
}
void double_to_bits(double val)
{
unsigned idx;
unsigned char arr[sizeof val];
memcpy (arr, &val, sizeof val);
printf("array is : %s\n", arr);
for (idx=CHAR_BIT * sizeof val; idx-- ; ) {
putc(
( arr[idx/CHAR_BIT] & (1u << (idx%CHAR_BIT) ) )
? '1'
: '0'
, stdout
);
}
}
What does arr[idx/CHAR_BIT] return? I understand say if idx = 63 then we get arr[7] but in print statements these seem to just give random integer values .
Also why does the & operand between arr[idx/CHAR_BIT] and (1u%CHAR_BIT) give 2 weird character symbols? How does the & operand work on these two values?
Thank you for your time and help.
This code defines vals to have one element:
double vals[] = { 10 };
This code uses vals as if it has four elements:
for (idx = 0; idx < 4; idx++ ) {
printf("\nvals[%u]= %+lf-->>", idx, vals[idx] );
double_to_bits(vals[idx] );
}
Because of that, the behavior of the program is not defined by the C standard, and different compilers will do different things. You have not shown us what output you get, so we have no way to analyze what your compiler did. Mine seems to figure that, since vals has only one element, it never needs to bother computing the value of idx in vals[idx]; it can always use vals[0]. So every iteration operates on the value 10. Your compiler may have loaded from memory outside the array and used different values.
What does arr[idx/CHAR_BIT] return?
CHAR_BIT is defined in <limits.h> to be the number of bits in a byte. Because of the definition unsigned char arr[sizeof val];, arr is an array with as many elements (each one byte) as there are bytes in a double. So, for example, if there are 8 bits in a byte and 8 bytes in a double, then arr has 8 8-bit elements, 64 bits total.
Using these example numbers, the for loop iterates idx through the numbers from 63 to 0. Then the code uses idx as a counter of the bits in arr. The expression idx/CHAR_BIT figures out which element of the array contains the bit numbered idx: Each array element has CHAR_BIT bits, bits 0-7 (when CHAR_BIT is 8) are in element 0, bits 8-15 are in element 1, bits 16-23 are in element 2, and so on. So dividing idx by CHAR_BIT and truncating to an integer (which is what the / operator does for integer operands) gives the index of the array element that has the bit with number idx.
Then arr[idx/CHAR_BIT] gets that element. Then we need to pick out the individual bit from that element. idx%CHAR_BIT takes the remainder of idx divided by CHAR_BIT, so it gives the number of a bit within a byte. Then 1u << (idx%CHAR_BIT) shifts 1 by that number. The result is number that, when expressed in binary, has a 1 in the bit with that number and a 0 in other bits.
Then the & operator ANDs that with the array element. If the array element has a 0 where the 1 has been shifted to, the result is zero. If the array element has a 1 where the 1 has been shifted to, the result is that bit (still in its position).
Then ? '1' : '0;' uses the result of that AND to select either the character '1' (if the result is not zero) or the character '0' (if the result is zero). That character is passed to putc for printing.
I understand say if idx = 63 then we get arr[7] but in print statements these seem to just give random integer values .
When the array bounds problem described above is corrected and double_to_bits is passed a valid value, it should print the bits that encoded the value of the double. In most C implementations, this will be 0100000000100100000000000000000000000000000000000000000000000000, which is the encoding in the IEEE-754 binary64 format, also called double precision.
Also why does the & operand between arr[idx/CHAR_BIT] and (1u%CHAR_BIT) give 2 weird character symbols?
You have not shown the weird character symbols or other output, so we have no output to interpret.
The statement printf("array is : %s\n", arr); prints arr as if it were a string containing printable characters, but it is used to contain “raw binary data,” so you should not expect that data to result in meaningful characters when printed. Remove that statement. Also, the fact that your program accessed vals out of bounds could cause other complications in output.
what does this do
while(*string) {
i = (i << 3) + (i<<1) + (*string -'0');
string++;
}
the *string -'0'
does it remove the character value or something?
This subtracts from the character to which string is pointing the ASCII code of the character '0'. So, '0' - '0' gives you 0 and so on and '9' - '0' gives you 9.
The entire loop is basically calculating "manually" the numerical value of the decimal integer in the string string points to.
That's because i << 3 is equivalent to i * 8 and i << 1 is equivalent to i * 2 and (i << 3) + (i<<1) is equivalent to i * 8 + i * 2 or i * 10.
Since the digits 0-9 are guaranteed to be stored contiguously in the character set, subtracting '0' gives the integer value of whichever character digit you have.
Let's say you're using ASCII:
char digit = '6'; //value of 54 in ASCII
int actual = digit - '0'; //'0' is 48 in ASCII, therefore `actual` is 6.
No matter which values the digits have in the character set, since they're contiguous, subtracting the beginning ('0') from the digit will give the digit you're looking for. Note that the same is NOT particularly true for the letters. Look at EBCDIC, for example.
It converts the ascii value of 0-9 characters to its numerical value.
ASCII value of '0' (character) is 48 and '1' is 49.
So to convert 48-56('0'-'9') to 0-9, you just need to subtract 48 from the ascii value.
that is what your code line [ *string -'0' ] is doing.
I'm trying to understand the following function which decides whether a bit is on:
int isBitISet( char ch, int i )
{
char mask = 1 << i ;
return mask & ch ;
}
First, why do I get a char? for ch=abcdefgh and i=5 the function suppose to return the fifth bit from the right (?) , d. so mask=00000001<<5=00100000, and 00100000 & abcdefgh = 00c00000.
Can you please explain me how come we get char and we can do all these shifts without any casting? how come we didn't get the fifth bit and why the returned value is really the Indication whether the bit is on or not?
Edit: the 'abcdefg' are just a symbols for the bits, I didn't mean to represent a string in a char type.
I used to think of a char as 'a' and not as an actual 8 bits, so probably this is the answer to my first question.
It won't give you the fifth bit. Binary numbers start at 20, so the first bit is actually indexed with 0, not with 1. It will give return you sixth bit instead.
Examples:
ch & (1 << 0); // first bit
ch & (1 << 1); // second bit
ch & ((1 << 3) | (1 << 2)); // third and fourth bit.
Also, a char is only an interpretation of a number. On most machines it has a size of 8 bit, which you can either interpret as a unsigned value (0 to 255) or signed value (-128 to 127). So basically it's an integer with a very limited range, thus you can apply bit shifting without casting.
Also, your function will return an integer value that equals zero if and only if the given bit isn't set. Otherwise it's a non-zero value.
The function may return a char, because the input it works on is also a char only. You certainly can not pass in ch=abcdefgh, because that would be a string of 8 chars.
You can do shifts on chars, because C allows to do it. char is just an 8-bit integer type so there's no need to disallow it.
You are right about the fact, that isBitISet(abcdefgh, 5) returns 00c00000 if the letters a, b, etc. are bits in the binary representation of numbers.
The return value is not the fifth bit from the right, it is the same number as in the input, but with all the bits but the fifth bit zeroed.
You also have to remember that numbering of bits goes from zero, so the fifth bit being c is correct, just as that the zeroth bit is h.
This example uses an integer type to represent a boolean value. This is common in C code prior to C99, as C didn't have the bool type.
If you treat your return value as a boolean value, remember that everything non-zero is true, and zero is false. Hence, the output of isBitISet is true for C if bit i is set, and false otherwise.
You should know by now that in computers, everything starts with 0. That is, bit number 5 is in fact the sixth bit (not the fifth).
Your analysis is actually correct, if you give it abcdefgh and 5, you get 00c00000.
When you do the "and":
return mask & ch;
since mask has type int, ch will also automatically be cast to int (same way as many other operators). That's why you don't need explicit casting.
Finally, the result of this function is in the form 0..0z0..0. If z, the bit you are checking for is 0, this value is 0 which is false as long as an if is concerned. If it is not zero, then it is true for an if.
Do:
return 0 != (mask & ch) ;
if you want a bool (0x00000000 or 0x00000001) return. mask & ch alone will give you the bit you're asking about at correct position.
(others said more than enuff about i=5 being sixth bit)
First of all, this function does not return the i-th bit, but tells you if that bit is on or off.
The usage of char mask is implementation depend here. Simply defines an 8-bit mask since the value on which to apply this mask is a char.
Why would you need a cast when 1 is a char? i is only an value for << operator.
ch=abcdefgh makes no sense as an input. ch is char, so ch can only be one character.
The working is as follows: first you construct a mask to zero all the bits you don't need. So for example if the input is ch = 204 (ch = 11001100) and we want to know if the 6th bit is on, so i = 5. So mask = 1 << 5 = 00100000. Then this mask is applied to the value with an AND operation. This will zero everything except the bit in question: 11001100 & 00100000 = 00000000 = 0. As 0 is false in C, then 6th bit is not set. Another example on same ch input and i = 6: mask = 1 << 6 = 01000000; 11001100 & 01000000 = 01000000 = 64, which is not 0, and thus true, so 7th bit is set.
I was reading a program in C (an implementation of a server/client communication) and I saw this:
for (i = 0; i < len; i++)
sprintf(nickmsg+i*2, "%02X", buf[i] & 0xFF);
What does this line do? I don't understand this especially: nickmsg+i*2.
nickmsg is a char table and i is an integer. If it was just nickmsg, ok I'll understand but there what's the aim of this line ?
Thanks.
Start at the address pointed to by nickmsg and then go an additional i * 2 * CHAR_BIT / 8 bytes in memory. From there, write the hex representation of buf[i] & 0xFF, which will occupy 2 * CHAR_BIT / 8 bytes. Repeat for each i.
Assuming buf looks like
buf[0] = 20
buf[1] = 12
Then the memory pointed to by nickmsg will look like:
nickmsg
|
|
|
+ + + + +
0 2 4 6 8
140C\
Where the \ is my nomenclature for the null-terminator that sprintf writes at the end.
It's converting the values in the buf array to their hexadecimal representation and storing them in the nickmsg array.
As it steps through each value in buf, it extracts the rightmost 8 bits by performing a bitwise AND with 0xFF, which is binary 1111 1111.
Then it uses the format string "%02X" to print each value as 2 hex digits.
It stores each pair of hex digits in the nickmsg array, then advances past them by using the index i*2.
nickmsg+i*2 is treating the nickmsg variable as a pointer to a C string table, then stepping through it 2 entries every loop.
I am trying to learn C for my class. One thing I need to know is given an array, I have to take information from two characters and store it in one bytes. For eg. if string is "A1B3C5" then I have to store A = 001 in higher 3bits and then store 1 in lower 5bits. I have to function that can get two chars from array at a time and print it here is that function,
void print2(char string[])
{
int i = 0;
int length = 0;
char char1, char2;
length = strlen(string);
for ( i = 0; i <length; i= i + 2)
{
char1 = string[i];
char2 = string[i+1];
printf("%c, %c\n", char1, char2);
}
}
but now i am not sure how to get it encoded and then decode again. Can anyone help me please?
Assuming an ASCII character set, subtract '#' from the letter and shift left five bits, then subtract '0' from the character representing the digit and add it to the first part.
So you've got a byte, and you want the following bit layout:
76543210
AAABBBBB
To store A, you would do:
unsigned char result;
int input_a = somevalue;
result &= 0x1F; // Clear the upper 3 bits.
// Store "A": make sure only the lower 3 bits of input_a are used,
// Then shift it by 5 positions. Finally, store it by OR'ing.
result |= (char)((input_a & 7) << 5);
To read it:
// Simply shift the byte by five positions.
int output_a = (result >> 5);
To store B, you would do:
int input_b = yetanothervalue;
result &= 0xE0; // Clear the lower 5 bits.
// Store "B": make sure only the lower 5 bits of input_b are used,
// then store them by OR'ing.
result |= (char)(input_b & 0x1F);
To read it:
// Simply get the lower 5 bits.
int output_b = (result & 0x1F);
You may want to read about the boolean operations AND and OR, bit shifting and finally bit masks.
First of all, one bit can only represent two states: 0 and 1, or TRUE and FALSE. What you mean is a Byte, which consists of 8 bits and can thus represent 2^8 states.
Two put two values in one byte, use logical OR (|) and bitwise shift (<< and >>).
I don't post the code here since you should learn this stuff - it's really important to know what bits and bytes are and how to work with them. But feel free to ask follow up question if something is not clear to you.