I'd like to take an int, and convert it into uint8_t array of hex numbers? The int is at maximum 8 bytes long in HEX after conversion. I was able to use a method that converts an int (19604) into a uint8_t array like this:
00-00-00-00-00-00-00-00-04-0C-09-04
But I need it to look like this:
00-00-00-00-00-00-00-00-00-00-4C-94
The algorithm I used was this:
void convert_file_size_to_hex(long int size)
{
size_t wr_len = 12;
long int decimalNumber, quotient;
int i=wr_len, temp;
decimalNumber = size;
quotient = decimalNumber;
uint8_t hexNum[wr_len];
memset(hexNum, 0, sizeof(hexNum));
while(quotient != 0) {
temp = quotient % 16;
hexNum[--i] = temp;
quotient /= 16;
}
How can I go about doing this? Should I use a different algorithm or should I try to bit shift the result? I'm kinda new to bit shifting in C so some help would be great. Thank you!
Consider the following code:
#include <stdio.h>
#include <string.h>
int main()
{
unsigned char hexBuffer[100]={0};
int n=19604;
int i;
memcpy((char*)hexBuffer,(char*)&n,sizeof(int));
for(i=0;i<4;i++)
printf("%02X ",hexBuffer[i]);
printf("\n");
return 0;
}
Use just a simple statement to convert int to byte buffer
memcpy((char*)hexBuffer,(char*)&n,sizeof(int));
You can use 8 instead of 4 while print the loop
Since n % 16 has a range of 0..15, inclusive, you are making an array of single hex digits from your number. If you would like to make an array of bytes, use 256 instead:
while(quotient != 0) {
temp = quotient % 256;
hexNum[--i] = temp;
quotient /= 256;
}
You can rewrite the same with bit shifts and bit masking:
while(quotient != 0) {
temp = quotient & 0xFF;
hexNum[--i] = temp;
quotient >>= 8;
}
To know how many bytes you need regardless of the system, use sizeof(int):
size_t wr_len = sizeof(int);
Use a union for this
union int_to_bytes {
int i;
uint8_t b[sizeof(int)];
};
union int_to_bytes test = { .i = 19604 };
int i = sizeof(test.b); // Little-Endian
while (i--)
printf("%hhx ", test.b[i]); // 0 0 4c 94
putchar('\n');
Related
I have a program that will take two 4-byte integers as input and I need to store these into integer arrays like so...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char *argv[]) {
int vals1[32], vals2[32];
int num1 = atoi(argv[1]);
int num2 = atoi(argv[2]);
// so argv[1] might be 47 and I would want to set the values of the vals1 array to reflect that in binary form
}
Any suggestions?
First task would be to convert a char * to an int, which you said you can. So here comes the next part i.e. getting the binary representation. For getting the binary representation of any data type, usage of Shift Operator is one of the best ways. And you can get it by performing shift on the data type and then performing Bitwise AND i.e. & with 1. For example, if n is an integer
int n = 47;
for (int i = 0; i < 32; i++)
{
/* It's going to print the values of bits starting from least significant. */
printf("Bit%d = %d\r\n", i, (unsigned int)((n >> i) & 1));
}
So, using shift operator, solution to your problem would be something like
void fun(int n1, int n2)
{
int i, argv1[32], argv2[32];
for (i = 0; i < 32; i++)
{
argv1[i] = ((unsigned int)n1 >> i) & 1;
argv2[i] = ((unsigned int)n2 >> i) & 1;
}
}
You have to be careful about the bit order i.e. which bit are being stored at which of the array index.
So I have a binary representation of a number as a character array. What I need to do is shift this representation to the right by 11 bits.
For example,
I have a char array which is currently storing this string: 11000000111001
After performing a bitwise shift, I will get 110 with some zeros before it.
I tried using this function but it gave me strange output:
char *shift_right(unsigned char *ar, int size, int shift)
{
int carry = 0; // Clear the initial carry bit.
while (shift--) { // For each bit to shift ...
for (int i = size - 1; i >= 0; --i) { // For each element of the array from high to low ...
int next = (ar[i] & 1) ? 0x80 : 0; // ... if the low bit is set, set the carry bit.
ar[i] = carry | (ar[i] >> 1); // Shift the element one bit left and addthe old carry.
carry = next; // Remember the old carry for next time.
}
}
return ar;
}
Any help on this would be very much appreciated; let me know if I'm not being clear.
They are just characters...
char *shift_right(unsigned char *ar, int size, int shift)
{
memmove(&ar[shift], ar, size-shift);
memset(ar, '0', shift);
return(ar);
};
Or, convert the string to a long-long, shift it, then back to a string:
char *shift_right(char *ar, int size, int shift)
{
unsigned long long x;
char *cp;
x=strtoull(ar, &cp, 2); // As suggested by 'Don't You Worry Child'
x = x >> shift;
while(cp > ar)
{
--cp;
*cp = (1 & x) ? '1' : '0';
x = x >> 1;
}
return(ar);
};
If you really want to use bitwise shifting, then you can't do it on a string. Simply not Possible!!
You have to convert it to integer (use strtol for that) then do bitwise shifting. After that, convert it back to string (no standard library function for that, use for loop).
I would advise to keep the code simple and readable.
#include <stdio.h>
#include <stdlib.h>
void shift_right (char* dest, const char* source, int shift_n)
{
uint16_t val = strtoul(source, NULL, 2);
val >>= shift_n;
for(uint8_t i=0; i<16; i++)
{
if(val & 0x8000) // first item of the string is the MSB
{
dest[i] = '1';
}
else
{
dest[i] = '0';
}
val <<= 1; // keep evaluating the number from MSB and down
}
dest[16] = '\0';
}
int main()
{
const char str [16+1] = "0011000000111001";
char str_shifted [16+1];
puts(str);
shift_right(str_shifted, str, 11);
puts(str_shifted);
return 0;
}
Briefly: Question is related to bitwise operations on hex - language C ; O.S: linux
I would simply like to do some bitwise operations on a "long" hex string.
I tried the following:
First try:
I cannot use the following because of overflow:
long t1 = 0xabefffcccaadddddffff;
and t2 = 0xdeeefffffccccaaadacd;
Second try: Does not work because abcdef are interpreted as string instead of hex
char* t1 = "abefffcccaadddddffff";
char* t2 = "deeefffffccccaaadacd";
int len = strlen(t1);
for (int i = 0; i < len; i++ )
{
char exor = *(t1 + i) ^ *(t2 + i);
printf("%x", exor);
}
Could someone please let me know how to do this? thx
Bitwise operations are usually very easily extended to larger numbers.
The best way to do this is to split them up into 4 or 8 byte sequences, and store them as an array of uints. In this case you need at least 80 bits for those particular strings.
For AND it is pretty simple, something like:
unsigned int A[3] = { 0xabef, 0xffcccaad, 0xddddffff };
unsigned int B[3] = { 0xdeee, 0xfffffccc, 0xcaaadacd };
unsigned int R[3] = { 0 };
for (int b = 0; b < 3; b++) {
R[b] = A[b] & B[b];
}
A more full example including scanning hex strings and printing them:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef unsigned int uint;
void long_Print(int size, const uint a[]) {
printf("0x");
for (int i = 0; i < size; i++) {
printf("%x", a[i]);
}
}
void long_AND(int size, const uint a[], const uint b[], uint r[]) {
for (int i = 0; i < size; i++) {
r[i] = a[i] & b[i];
}
}
// Reads a long hex string and fills an array. Returns the number of elements filled.
int long_Scan(int size, const char* str, uint r[]) {
int len = strlen(str);
int ri = size;
for (const char* here = &str[len]; here != str; here -= 8) {
if (here < str) {
char* tmp = (char*)malloc(4);
tmp[0] = '%';
tmp[1] = (char)(str - here + '0');
tmp[2] = 'x';
tmp[3] = '\0';
sscanf(str, tmp, &r[ri--]);
free(tmp);
break;
}
else {
sscanf(here, "%8x", &r[ri--]);
}
}
for (; ri >= 0; ri--) {
r[ri] == 0;
}
return size - ri;
}
int main(int argc, char* argv[])
{
uint A[3] = { 0 };
uint B[3] = { 0 };
uint R[3] = { 0 };
long_Scan(3, "abefffcccaadddddffff", A);
long_Scan(3, "deeefffffccccaaadacd", B);
long_Print(3, A);
puts("\nAND");
long_Print(3, B);
puts("\n=");
long_AND(3, A, B, R);
long_Print(3, R);
getchar();
return 0;
}
You'll certainly need to use a library that can handle arbitrarily long integers. Consider using libgmp: http://gmplib.org/
Before you can do any sort of bitwise operations, you need to be working with integers. "abeffccc" is not an integer. It is a string. You need to use something like strtol
to first convert the string to an integer.
If your values are too big to fit into a 64-bit long long int (0xFFFFFFFF,FFFFFFFF) then you'll need to use a Big Integer library, or something similar, to support arbitrarily large values. As H2CO3 mentioned, libgmp is an excellent choice for large numbers in C.
Instead of using unsigned long directly, you could try using an array of unsigned int. Each unsigned int holds 32 bits, or 8 hex digits. You would therefore have to chop-up your constant into chunks of 8 hex digits each:
unsigned int t1[3] = { 0xabef , 0xffcccaad , 0xddddffff };
Note that for sanity, you should store them in reverse order so that the first entry of t1 contains the lowest-order bits.
I wrote this code to do the IEEE 754 floating point arithmetic on a 4byte string.
It takes in the bytes, converts them to binary and with the binary I get the sign, exponent, and mantissa and then do the calculation.
It all works just about perfectl, 0xDEADBEEF gives me 6259853398707798016 and the true answer is 6.259853398707798016E18, now these are same values and I wont have anything this large in the project I'm working with, all other smaller values put the decimal in the correct place.
Here is my code:
float calcByteValue(uint8_t data[]) {
int i;
int j = 0;
int index;
int sign, exp;
float mant;
char bits[8] = {0};
int *binary = malloc(32*sizeof *binary);
for (index = 0;index < 4;index++) {
for (i = 0;i < 8;i++,j++) {
bits[i] = (data[index] >> 7-i) & 0x01;
if (bits[i] == 1) {
binary[j] = 1;
} else {
binary[j] = 0;
}
}
printf("\nindex(%d)\n", index);
}
sign = getSign(&(binary[0]));
mant = getMant(&(binary[0]));
exp = getExp(&(binary[0]));
printf("\nBinary: ");
for (i = 0;i < 32;i++)
printf("%d", binary[i]);
printf("\nsign:%d, exp:%d, mant:%f\n",sign, exp, mant);
float f = pow(-1.0, sign) * mant * pow(2,exp);
printf("\n%f\n", f);
return f;
}
//-------------------------------------------------------------------
int getSign(int *bin) {
return bin[0];
}
int getExp (int *bin) {
int expInt, i, b, sum;
int exp = 0;
for (i = 0;i < 8;i++) {
b = 1;
b = b<<(7-i);
if (bin[i+1] == 1)
exp += bin[i+1] * b;
}
return exp-127;
}
float getMant(int *bin) {
int i,j;
float b;
float m;
int manBin[24] = {0};
manBin[0] = 1;
for (i = 1,j=9;j < 32;i++,j++) {
manBin[i] = bin[j];
printf("%d",manBin[i]);
}
for (i = 0;i < 24;i++) {
m += manBin[i] * pow(2,-i);;
}
return m;
}
Now, my teacher told me that there is a much easier way where I can just take in the stream of bytes, and turn it into a float and it should work. I tried doing it that way but could not figure it out if my life depended on it.
I'm not asking you to do my homework for me, I have it done and working, but I just need to know if I could of done it differently/easier/more efficiently.
EDIT: there are a couple special cases I need to handle, but it's just things like if the exponent is all zeros blah blah blah. Easy to implement.
The teacher probably had this in mind:
char * str; // your deadbeef
float x;
memcpy(&x, str, sizeof(float));
I would advise against it, for the issues with endianness. But if your teacher wants it, he shall have it.
I think you want a union - just create a union where one member is a 4 character array, and the other a float. Write the first, then read the second.
Looking at what your code does then the "4 byte string" looks like it already contains the binary representation of a 32 bit float, so it already exists in memory at the address specified by data in big endian byte order.
You could probably cast the array data to a float pointer and dereference that (if you can assume the system you are running on is big endian and that data will be correctly aligned for the float type on your platform).
Alternatively if you need more control (for example to change the byte order or ensure alignment) you could look into type punning using a union of a uint8_t array and a float. Copy the bytes into your union's uint8_t array and then read the float member.
Here is my working code:
unsigned char val[4] = {0, 0, 0xc8, 0x41};
cout << val << endl;
cout << "--------------------------------------------" << endl;
float f = *(float*)&val;
cout << f << endl;
return 0;
I wrote a function to get the machine word in C yesterday, but it seems that there is something wrong in it.
Here is the code:
unsigned machineword()
{
int i = 1;
unsigned temp;
while (temp > 0)
{
i++;
temp = (unsigned)(~0 >> i);
}
return i;
}
The simplest way to get the width of unsigned int is (sizeof(unsigned)*CHAR_BIT).
EDIT: as noted by pmg, you should be aware of the theoretical difference between the size an unsigned takes in memory and the number of bits available for computing with. Your original code tries to compute the latter, and so does the program below. The above trick computes the space occupied in memory.
It is not very convenient to compute this number with >> as it is forbidden in C to use >> with a number equal to or larger than the size in bits of the type you are shifting. You can work around this, if you know that long long is strictly larger than int, by computing with unsigned long long:
unsigned machineword()
{
int i = 1;
unsigned temp=1;
while (temp > 0)
{
i++;
temp = (unsigned)(((unsigned long long)~(0U)) >> i);
}
return i;
}
The simplest way to avoid the UB when shifting for too large value while keeping your structure is:
unsigned machineword()
{
unsigned i = 0;
unsigned temp = ~0U;
while (temp > 0)
{
i++;
temp >>= 1;
}
return i;
}
To calculate the number of bits, you can use CHAR_BIT or UINT_MAX.
The CHAR_BIT approach gives you the number of bits each value occupies in memory.
The UINT_MAX approach gives you the effective available bits.
Usually both values will be the same
#include <limits.h>
#include <stdio.h>
int main(void) {
unsigned tmp = UINT_MAX;
int i = 0;
while (tmp) {
i++;
tmp /= 2;
}
printf("value bits in a unsigned: %d\n", i);
printf("memory bits in a unsigned: %d\n", CHAR_BIT * (int)sizeof (unsigned));
return 0;
}