I wrote the following function. This function receives the address of a hex value e.g. 0x4571 and calculates with Day, Month and Year from the bit positions of the hex value.
void fat_dir_date(char *dateAr) {
const unsigned int MaskDayOfMonth = 0x1F; //0000000000011111
const unsigned int MaskMonthOfYear = 0x1E0; //0000000111100000
const unsigned int MaskYear = 0xFE00; //1111111000000000
unsigned int DayOfMonth = hex & MaskDayOfMonth; //AND Bit Operation
unsigned int MonthOfYear = hex & MaskMonthOfYear; //AND Bit Operation
MonthOfYear = MonthOfYear >> 5; //Bitshift to right position
unsigned int Year = hex & MaskYear; //AND Bit Operation
Year = Year >> 9; //Bitshift to right position
printf("%d.%d.%d", DayOfMonth, MonthOfYear, 1980+Year);
}
The calculation works fine. I get the right numbers in the integer DayOfMonth,MonthOfYear and Year. But instead of printing them out with printf, I want to return the values to the caller function. In the best way in concatenated in a single value or string.
How is the best way to solve this in C?
You have several options there:
Create a struct that has the three fields, and return it,
Let the caller pass you the struct that you fill in,
Let the caller pass you a string buffer to which you print using sprintf, or
Create a string dynamically, print to it, and return.
The first option is clean and easy to understand. It requires some copying, but it is fine for small structures like the one that you need:
struct DateTime {
int DayOfMonth;
int MonthOfYear;
int Year;
};
struct DateTime fat_dir_date(unsigned int hex) {
struct DateTime res;
res.DayOfMonth = ...
res.MonthOfYear = ...
res.Year = ...
return res;
}
If you need to print the data and you don't need to use the numeric values, I think this:
char * fat_dir_date(char *dateAr,unsigned int hex) {
const unsigned int MaskDayOfMonth = 0x1F; //0000000000011111
const unsigned int MaskMonthOfYear = 0x1E0; //0000000111100000
const unsigned int MaskYear = 0xFE00; //1111111000000000
unsigned int DayOfMonth = hex & MaskDayOfMonth; //AND Bit Operation
unsigned int MonthOfYear = hex & MaskMonthOfYear; //AND Bit Operation
MonthOfYear = MonthOfYear >> 5; //Bitshift to right position
unsigned int Year = hex & MaskYear; //AND Bit Operation
Year = Year >> 9; //Bitshift to right position
sprintf(dateAr,"%02u.%02u.%4u", DayOfMonth,MonthOfYear, 1980+Year);
return dateAr;
}
int main(void)
{
char dateAr[11];
unsigned int hex=0x1010; //Random :)
printf("%s\n" , fat_dir_date(dateAr,hex))
return 0;
}
Related
Actually, I have to convert from command arguments which are three strings to bit field(three unsigned integers inside). This program is going to convert from bits into float. I firstly thought about using array to store the three arguments,but I don't really know how to convert from array to unsigned int. Should I just use atoi to change arg into int and then directly into unsigned int? It doesn't word on my computer. Got no idea.
Union32 getBits(char *sign, char *exp, char *frac)
{
Union32 new;
// this line is just to keep gcc happy
// delete it when you have implemented the function
//new.bits.sign = new.bits.exp = new.bits.frac = 0;
new.bits.sign = *(unsigned int *)atoi(sign);
new.bits.exp = *(unsigned int *)atoi(exp);
new.bits.frac = *(unsigned int *)atoi(frac);
//int i ;
//int balah[8] = {};
//for(i = 0; i < 8; i++){
//balah[i] = sign[i];
//}
//int j ;
//int bili[23] = {};
//for(j = 0; j < 23; j++){
//bili[j] = sign[j];
//}
//convert array into unsigned integer?
printf("%u %u %u\n", new.bits.sign, new.bits.exp, new.bits.frac);
// convert char *sign into a single bit in new.bits
// convert char *exp into an 8-bit value in new.bits
// convert char *frac into a 23-bit value in new.bits
enter code here
return new;
}
The following are the details about the typedef and unions that needed in this program, also the four functions in this program.
typedef uint32_t Word;
struct _float {
// define bit_fields for sign, exp and frac
// obviously they need to be larger than 1-bit each
// and may need to be defined in a different order
unsigned int sign:1, exp:8, frac:23;
};
typedef struct _float Float32;
union _bits32 {
float fval; // interpret the bits as a float
Word xval; // interpret as a single 32-bit word
Float32 bits; // manipulate individual bits
};
typedef union _bits32 Union32;
void checkArgs(int, char **);
Union32 getBits(char *, char *, char *);
char *showBits(Word, char *);
int justBits(char *, int);
getBits asks us to convert bits into float,
and showBits asks us to convert float into bits.
assuming the correct typedefs in your code:
new.bits.sign = (unsigned int)atoi(sign);
new.bits.exp = (unsigned int)atoi(exp);
new.bits.frac = (unsigned int)atoi(frac);
I'm trying to convert an unsigned char array buffer into a signed int (vice versa).
Below is a demo code:
int main(int argv, char* argc[])
{
int original = 1054;
unsigned int i = 1054;
unsigned char c[4];
int num;
memcpy(c, (char*)&i, sizeof(int));
//num = *(int*) c; // method 1 get
memcpy((char *)&num, c, sizeof(int)); // method 2 get
printf("%d\n", num);
return 0;
}
1) Which method should I use to get from unsigned char[] to int?
method 1 get or method 2 get?
(or any suggestion)
2) How do I convert the int original into an unsigned char[]?
I need to send this integer via a buffer that only accepts unsigned char[]
Currently what i'm doing is converting the int to unsigned int then to char[], example :
int g = 1054;
unsigned char buf[4];
unsigned int n;
n = g;
memcpy(buf, (char*)&n, sizeof(int));
Although it works fine but i'm not sure if its the correct way or is it safe?
PS. I'm trying to send data between 2 devices via USB serial communication (between Raspberry Pi & Arduino)
Below approach will work regardless of endianness on machines (assuming sizeof(int)==4):
unsigned char bytes[4];
unsigned int n = 45;
bytes[3] = (n >> 24) & 0xFF;
bytes[2] = (n >> 16) & 0xFF;
bytes[3] = (n >> 8) & 0xFF;
bytes[0] = n & 0xFF;
Above code converts integer to byte array in little endian way. Here is link also with more information.
For reverse operation, see the answers here.
The approach you have with memcpy may give different results on different computers. Because memcpy will copy whatever is there in source address to destionation, and depending if computer is little endian or big endian, there maybe a LSB or MSB at the starting source address.
You could store both int (or unsigned int) and unsigned char array as union. This method is called type punning and it is fully sanitized by standard since C99 (it was common practice earlier, though). Assuming that sizeof(int) == 4:
#include <stdio.h>
union device_buffer {
int i;
unsigned char c[4];
};
int main(int argv, char* argc[])
{
int original = 1054;
union device_buffer db;
db.i = original;
for (int i = 0; i < 4; i++) {
printf("c[i] = 0x%x\n", db.c[i]);
}
}
Note that values in array are stored due to byte order, i.e. endianess.
I have code snippet as Below
unsigned char p = 0;
unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(p=0;p<4;p++)
{
m |= t[p];
printf("%c",m);
m = m << 2;
}
Can anybody help me in solving this. consider i have an ascii value abcd stored in an array t[]. I want to store the same value in 'm'. m is my unsigned int variable . which stores the major number. when i copy the array into m & print m . m should print abcd. can anybody state their logic.
As I understand you, you want to encode the 4 characters into a single int.
Your bit shifting is not correct. You need to shift by 8 bits rather than 2. You also need to perform the shifting before the bitwise or. Otherwise you shift too far.
And it makes more sense, in my view, to print the character rather than m.
#include <stdio.h>
int main(void)
{
const unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(int p=0;p<4;p++)
{
m = (m << 8) | t[p];
printf("%c", t[p]);
}
printf("\n%x", m);
return 0;
}
Why not just look at the t array as an unsigned int?:
unsigned int m = *(unsigned int*)t;
Or you could use an union for nice access to the same memory block in two different ways, which I think is better than shifting bits manually.
Below is an union example. With unions, both the t char array and the unsigned int are stored in the same memory blob. You get a nice interface to each, and it lets the compiler do the bit shifting (more portable, I guess):
#include <stdio.h>
typedef union {
unsigned char t[4];
unsigned int m;
} blob;
int main()
{
blob b;
b.t[0]='a';
b.t[1]='b';
b.t[2]='c';
b.t[3]='d';
unsigned int m=b.m; /* m holds the value of blob b */
printf("%u\n",m); /* this is the t array looked at as if it were an unsignd int */
unsigned int n=m; /* copy the unsigned int to another one */
blob c;
c.m=n; /* copy that to a different blob */
int i;
for(i=0;i<4;i++)
printf("%c\n",c.t[i]); /* even after copying it as an int, you can still look at it as a char array, if you put it into the blob union -- no manual bit manipulation*/
printf("%lu\n", sizeof(c)); /* the blob has the bytesize of an int */
return 0;
}
Simply assign t[p] to m.
m = t[p];
this will implicitly promote char to unsigned int.
unsigned char p = 0;
unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(p=0;p<4;p++)
{
m = t[p];
printf("%c",m);
}
I have a unsigned char array containing the following value : "\x00\x91\x12\x34\x56\x78\x90";
That is number being sent in Hexadecimal format.
Additionally, it is in BCD format : 00 in byte, 91 in another byte (8 bits)
On the other side I require to decode this value as 0091234567890.
I'm using the following code:
unsigned int conver_bcd(char *p,size_t length)
{
unsigned int convert =0;
while (length--)
{
convert = convert * 100 + (*p >> 4) * 10 + (*p & 15);
++p
}
return convert;
}
However, the result which I get is 1430637214.
What I understood was that I'm sending hexadecimal values (\x00\x91\x12\x34\x56\x78\x90) and my bcd conversion is acting upon the decimal values.
Can you please help me so that I can receive the output as 00911234567890 in Char
Regards
Karan
It looks like you are simply overflowing your unsigned int, which is presumably 32 bits on your system. Change:
unsigned int convert =0;
to:
uint64_t convert = 0;
in order to guarantee a 64 bit quantity for convert.
Make sure you add:
#include <stdint.h>
Cast char to unsigned char, then print it with %02x.
#include <stdio.h>
int main(void)
{
char array[] = "\x00\x91\x12\x34\x56\x78\x90";
int size = sizeof(array) - 1;
int i;
for(i = 0; i < size; i++){
printf("%02x", (unsigned char )array[i]);
}
return 0;
}
Change return type to unsigned long long to insure you have a large enough integer.
Change p type to an unsigned type.
Print value with leading zeros.
unsigned long long conver_bcd(const char *p, size_t length) {
const unsigned char *up = (const unsigned char*) p;
unsigned long long convert =0;
while (length--) {
convert = convert * 100 + (*up >> 4) * 10 + (*up & 15);
++up;
}
return convert;
}
const char *p = "\x00\x91\x12\x34\x56\x78\x90";
size_t length = 7;
printf( "%0*llu\n", (int) (length*2), conver_bcd(p, length));
// 00911234567890
I'm working on a C project and I have some instructions of type:
add $1 $2 $3
So I'm reading the line as a string, parsing through it and have a corresponding integer for add, say - 2. Could anyone please tell me how I could convert this to binary in order to write it to a file?
The registers are 5 bits and the operation is 6 bits. The total will be 32 (the last 10 bits are unused).
So the registers are stored in say op[] = "2", char r1[] = "1", char r2[] = "2" etc (note that register number can be as high as 31). Could anyone give me an example for a function that would convert this to binary in the format 000010 00001 00010 00011 0000000000
The easiest way will be using a bit field:
struct code {
unsigned opcode : 6;
unisgned operand1 : 5;
unisgned operand2 : 5;
unisgned operand2 : 5;
} test_code;
Now you can simply assign to the different members:
test_code.opcode = 0x02;
test_code.operator1 = 0x01;
test_code.operator2 = 0x02;
test_code.operator3 = 0x03;
atoi(op) will give you 2, so you can just string it together
As far as putting it into that structure you want, just create a structure that has bitfields in it and place it in a union with a 32 bit unsigned integer, and you can take the value directly.
Quick pseudo code
const char* int32_to_bin(int32_t value) {
int pos = 0;
char output[33];
while(value > 0) {
if (value & 1) output[pos++] = '1';
else output[pos++] = '0';
value >>= 1;
}
output[pos] = 0;
return output;
}
What you're asking is a C question but you tag as objective-c so I'll cover both.
C:
These variables such as op[].. are really defined as like char op[..] (not sure if your length), which are C strings of course.
So the operation is 6 bit and each register is 5 bits, that's 15 + 6 = 21 bit word. I'll assume the top 11 bits are zeroes.
What you need are 4 more variables that are integers:
int opint; int r0int; int r1int; int r2int;
You want the integer value of those strings to go in to those integers. You can use atoi() to achieve this, such as opint = atoi(op);
Now that you've got your integers derived from strings, you need to create the 32 bit word. The easiest way to do this is to first create one integer that holds those bits in the right place. You can do it (assuming 32 bit integers) like this:
int word = 0;
word |= ((opint & 0x3f) << (21 - 6))) |
(r0int & 0x1f) << (21 - 11)) |
(r1int & 0x1f) << (21 - 16))
(r2int & 0x1f));
Where the << is shifting in to place. After this, you should have the word integer properly formed. Next, just turn it in to a binary representation (if that's even necessary? Not sure on your application)
Objective-C
The only difference is that I assume those strings start as NSString *op; etc. In this case, get the integers by opint = [op intValue];, then form the word as I describe.
This code will convert a string to binary
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* stringToBinary(char* s) ;
void binchar(char output[], char character);
void itoa(int value, char* str, int base);
int main(int argc, char const *argv[])
{
printf("%s\n", stringToBinary("asdf") );
}
char* stringToBinary(char* s) {
if(s == NULL) return 0; /* no input string */
size_t len = strlen(s);
char *binary = malloc(len*8 + 1); // each char is one byte (8 bits) and + 1 at the end for null terminator
int i =0;
char output[9];
for(i=0; i< len; i++){
binchar(output, s[i]);
strcat(binary,output);
}
return binary;
}
void binchar(char output[], char character)
{
//char output[9];
itoa(character, output, 2);
}
// since GCC is not fully supporting itoa function here is its implementaion
// itoa implementation is copied from here http://www.strudel.org.uk/itoa/
void itoa(int value, char* str, int base) {
static char num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
char* wstr=str;
int sign;
// Validate base
if (base<2 || base>35){ *wstr='\0'; return; }
// Take care of sign
if ((sign=value) < 0) value = -value;
// Conversion. Number is reversed.
do *wstr++ = num[value%base]; while(value/=base);
if(sign<0) *wstr++='-';
*wstr='\0';
// Reverse string
void strreverse(char* begin, char* end);
strreverse(str,wstr-1);
}
void strreverse(char* begin, char* end) {
char aux;
while(end>begin)
aux=*end, *end--=*begin, *begin++=aux;
}