I'm trying to convert ASCII strings into Binary so i can add Parity to it (Hamming Code). But the output is not right at all.
If i enter 'A' on the input it should return:
01000001
and i've tried it with 'B' but it doesn't return that
unsigned char bits[8];
for(int i = 8; i >= 1; i--){
i expect the output to be 01000001 for 'A'
but the actual output is 00100000
Same for ABC or B or C
i is off by one, so you are accessing elements bitC[8] to bitC[1] (even though bitC[8] is out of bounds), and you are printing bits 8 to 1 instead of bits 7 to 0.
Replace
for(int i = 8; i >= 1; i--){
with
for(int i = 8; i--; ){
Related
I got this from somewhere but i don't kind of understand the meaning behind it.
How does this actually works?
void itox(unsigned int i, char *s)
{
unsigned char n;
s += 4;
*s = '\0';
for (n = 4; n != 0; --n) {
*--s = "0123456789ABCDEF"[i & 0x0F];
i >>= 4;
}
}
Thank you.
It assumes that s is a buffer of length 5 (including the null terminator) and writes the hex representation of i there. The result is the hex representation of i modulo 65536 (for lots of old systems, unsigned int has a range of 0 to 65535).
s += 4;
*s = '\0';
This goes to the end of s and puts a null terminator there.
for (n = 4; n != 0; --n) {
Now we loop backwards through the result string and fill in the appropriate char.
"0123456789ABCDEF"[i & 0x0F];
This selects the correct char. i & 0x0F gets the least significant hex value and by using that as a subscript for array access on "0123456789ABCDEF", the respective char is obtained.
*--s = ...
The char that is obtained is put in the correct place and the pointer is decreased again so the next position can be filled in the next run through the loop.
i >>= 4;
We now shift the number by four bits, removing the four bits we just converted into a hex digit. Now the next four bits will be the least significant hex digit.
Example
let's take the number 58008. In hex it is 0xE298. Mod 16 it is 8, so "0123456789ABCDEF"[8]; gets "8".
Then we shift it four bits, resulting in 3625. Mod 16 that's 9, and we get the "9". After the next shift we get 226, which mod 16 is 2, and one shift later we get 14. "0123456789ABCDEF"[14] is "E".
Assemble those results backwards and you get E298.
The interesting part here is
*--s = "0123456789ABCDEF"[i & 0x0F];
Here "0123456789ABCDEF" is a string literal which is stored in the compiler memory.
We are accessing this literal as an array. So, "0123456789ABCDEF"[0] will be the character '0' and "0123456789ABCDEF"[1] will be '1'
With that information, we can easily analyse the entire code.
s += 4; //Increment pointer s by 4
*s = '\0'; // last value to be '\0' to end the string
for (n = 4; n != 0; --n) {
*--s = "0123456789ABCDEF"[i & 0x0F];
i >>= 4;
}
// say i is 0x231
// For n == 4, i & 0x0F will be 1,
// *--s will point s to the third element in the array, and
// this will be assigned to 1.
// i <<4 will be i/16, so i will be 0x23
// for n == 3,
// *--s will point to second element of array, which will be 3.
// and so on.
Finally what you get is the hexadecimal value of the integer in s
#include <stdio.h>
void f1(char* str, int index)
{
*(str + index) &= ~32;
}
int main()
{
char arr[] = "gatecsit";
f1(arr, 0);
printf("%s", arr);
return 0;
}
How is function f1() working?
Being specific *(str + index) &= ~32; this one....
thanks
The expression
*(str + index)
is equivalent to
str[index]
So the character at position index is changed the following way
*(str + index) &= ~32;
In the ASCII table lower case letters differ from upper case letters by having one more set bit. For example the lower case letter 'a' has the code in hex 61 while the upper case letter 'A" has the code in hex 41. So the difference is equal to the value in hex 20 that in decimal is equal to 32.
So the original expression resets the corresponding bit in the character to 0 converting a lower case letter to the upper case letter.
I think f1() capitalizes the first letter of the string by exploiting a property of ASCII that means that corresponding lower and upper-case letters differ by 32. For example the code for 'A' is 65, while that for 'a' is 97. The '&= ~32' bit of the code will turn of bit-5 of the ASCII representation of the character str[index], which should turn the 'g' into 'G'. This should be fine for strings that contain only ordinary letters, but will have strange effects on digits and punctuation characters.
The code removes 1 bit from the character
effectively subtracting 32 from the byte or 0x20.
#include <stdio.h>
#include <string.h>
void f1(char* str, int index)
{
// The code removes 1 bit from the character at the position `str[index]`
// effectively subtracting 32 from that character
// Capital letters in ASCII are apart by 32 (0x20) from small letters
// Since 'a' = 0x61 and 'A' = 0x41 'a' - 32 = 'A'
// Since 'b' = 0x62 and 'B' = 0x42 'b' - 32 = 'B'
// `~` is a binary negation operator 0 -> 1; 1 -> 0
// `&` is a binary AND
// x &= y; is equivalent to x = x & y;
// ~0x20 = 0b11011111
*(str + index) &= ~0x20; // 0x20 = 32;
}
int main()
{
int i;
char arr[] = "gatecsit";
size_t len = strlen(arr);
for(i = 0; i< len; i++)
printf(" %c " , arr[i]);
printf("\n");
for(i = 0; i< len; i++)
printf(" %X" , arr[i]);
printf("\n");
// convert all letters:
for(i = 0; i< len; i++)
f1(arr, i);
printf("\n");
for(i = 0; i< len; i++)
printf(" %c " , arr[i]);
printf("\n");
for(i = 0; i< len; i++)
printf(" %X" , arr[i]);
return 0;
}
Output:
The small and capital are letters apart by 0x20 (or 32 decimal).
This can be clearly seen from this printout:
g a t e c s i t
67 61 74 65 63 73 69 74
G A T E C S I T
47 41 54 45 43 53 49 54
Perhaps this task is a bit more complicated than what I've written below, but the code that follows is my take on decimal to BCD. The task is to take in a decimal number, convert it to BCD and then to ASCII so that it can be displayed on a microcontroller. As far as I'm aware the code works sufficiently for the basic operation of converting to BCD however I'm stuck when it comes to converting this into ASCII. The overall output is ASCII so that an incremented value can be displayed on an LCD.
My code so far:
int dec2bin(int a){ //Decimal to binary function
int bin;
int i =1;
while (a!=0){
bin+=(a%2)*i;
i*=10;
a/=2;
}
return bin;
}
unsigned int ConverttoBCD(int val){
unsigned int unit = 0;
unsigned int ten = 0;
unsigned int hundred = 0;
hundred = (val/100);
ten = ((val-hundred*100)/10);
unit = (val-(hundred*100+ten*10));
uint8_t ret1 = dec2bin(unit);
uint8_t ret2 = dec2bin((ten)<<4);
uint8_t ret3 = dec2bin((hundred)<<8);
return(ret3+ret2+ret1);
}
The idea to convert to BCD for an ASCII representation of a number is actually the "correct one". Given BCD, you only need to add '0' to each digit for getting the corresponding ASCII value.
But your code has several problems. The most important one is that you try to stuff a value shifted left by 8 bits in an 8bit type. This can never work, those 8 bits will be zero, think about it! Then I absolutely do not understand what your dec2bin() function is supposed to do.
So I'll present you one possible correct solution to your problem. The key idea is to use a char for each individual BCD digit. Of course, a BCD digit only needs 4 bits and a char has at least 8 of them -- but you need char anyways for your ASCII representation and when your BCD digits are already in individual chars, all you have to do is indeed add '0' to each.
While at it: Converting to BCD by dividing and multiplying is a waste of resources. There's a nice algorithm called Double dabble for converting to BCD only using bit shifting and additions. I'm using it in the following example code:
#include <stdio.h>
#include <string.h>
// for determining the number of value bits in an integer type,
// see https://stackoverflow.com/a/4589384/2371524 for this nice trick:
#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))
// number of bits in unsigned int:
#define UNSIGNEDINT_BITS IMAX_BITS((unsigned)-1)
// convert to ASCII using BCD, return the number of digits:
int toAscii(char *buf, int bufsize, unsigned val)
{
// sanity check, a buffer smaller than one digit is pointless
if (bufsize < 1) return -1;
// initialize output buffer to zero
// if you don't have memset, use a loop here
memset(buf, 0, bufsize);
int scanstart = bufsize - 1;
int i;
// mask for single bits in value, start at most significant bit
unsigned mask = 1U << (UNSIGNEDINT_BITS - 1);
while (mask)
{
// extract single bit
int bit = !!(val & mask);
for (i = scanstart; i < bufsize; ++i)
{
// this is the "double dabble" trick -- in each iteration,
// add 3 to each element that is greater than 4. This will
// generate the correct overflowing bits while shifting for
// BCD
if (buf[i] > 4) buf[i] += 3;
}
// if we have filled the output buffer from the right far enough,
// we have to scan one position earlier in the next iteration
if (buf[scanstart] > 7) --scanstart;
// check for overflow of our buffer:
if (scanstart < 0) return -1;
// now just shift the bits in the BCD digits:
for (i = scanstart; i < bufsize - 1; ++i)
{
buf[i] <<= 1;
buf[i] &= 0xf;
buf[i] |= (buf[i+1] > 7);
}
// shift in the new bit from our value:
buf[bufsize-1] <<= 1;
buf[bufsize-1] &= 0xf;
buf[bufsize-1] |= bit;
// next bit:
mask >>= 1;
}
// find first non-zero digit:
for (i = 0; i < bufsize - 1; ++i) if (buf[i]) break;
int digits = bufsize - i;
// eliminate leading zero digits
// (again, use a loop if you don't have memmove)
// (or, if you're converting to a fixed number of digits and *want*
// the leading zeros, just skip this step entirely, including the
// loop above)
memmove(buf, buf + i, digits);
// convert to ascii:
for (i = 0; i < digits; ++i) buf[i] += '0';
return digits;
}
int main(void)
{
// some simple test code:
char buf[10];
int digits = toAscii(buf, 10, 471142);
for (int i = 0; i < digits; ++i)
{
putchar(buf[i]);
}
puts("");
}
You won't need this IMAX_BITS() "magic macro" if you actually know your target platform and how many bits there are in the integer type you want to convert.
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;
}
How can I convert a hexadecimal (unsigned char type) to decimal (int type) in AVR Studio?
Are there any built-in functions available for these?
On AVRs, I had problems using the traditional hex 2 int approach:
char *z="82000001";
uint32_t x=0;
sscanf(z, "%8X", &x);
or
x = strtol(z, 0, 16);
They simply provided the wrong output, and didn't have time to investigate why.
So, for AVR Microcontrollers I wrote the following function, including relevant comments to make it easy to understand:
/**
* hex2int
* take a hex string and convert it to a 32bit number (max 8 hex digits)
*/
uint32_t hex2int(char *hex) {
uint32_t val = 0;
while (*hex) {
// get current character then increment
char byte = *hex++;
// transform hex character to the 4bit equivalent number, using the ascii table indexes
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
// shift 4 to make space for new digit, and add the 4 bits of the new digit
val = (val << 4) | (byte & 0xF);
}
return val;
}
Example:
char *z ="82ABC1EF";
uint32_t x = hex2int(z);
printf("Number is [%X]\n", x);
Will output:
EDIT: sscanf will also work on AVRs, but for big hex numbers you'll need to use "%lX", like this:
char *z="82000001";
uint32_t x=0;
sscanf(z, "%lX", &x);