Unable to extract byte array value from int value - c

A union is defined, and given an integer value. The required size of array is estimated. Following the value is defined to the union. However, the byte array values are not able to be printed (ie. the last portion of the following code is not printing).
Given:
union {
unsigned int integer;
//unsigned char byte[4];
unsigned char* byte;
} foo;
In main()
int i;
int numberOfBytes = 1;
int targetValue = 123456789;
int sum = 0;
sum = pow(16, numberOfBytes);
while (sum < targetValue) {
//printf("Trying value: %d \n", (16^numberOfBytes));
numberOfBytes++;
sum += pow(16, numberOfBytes);
}
numberOfBytes++; // add 1 more byte space
printf("Number of Bytes: %d \n", numberOfBytes);
printf("Sum: %d \n", sum);
foo.byte = malloc(sizeof(unsigned char)*numberOfBytes);
if (foo.byte == NULL)
printf("malloc fail\n");
// clear foo
for (i=numberOfBytes; i >= 0;i--) {
foo.byte[i] = 0;
}
foo.integer = targetValue;
printf("Trying value: %d \n", foo.integer);
The following is not printing:
for (i=numberOfBytes; i >= 0;i--) {
printf("%x ", foo.byte[i]);
} printf("\n");

In your union, foo.byte is a pointer to an area of memory. This:
foo.byte = malloc(sizeof(unsigned char)*numberOfBytes);
is setting foo.byte to a pointer to an area of memory which you dynamically allocated. Then this:
foo.integer = targetValue;
is overwriting that pointer with the value.
Then this:
for (i=numberOfBytes; i >= 0;i--) {
printf("%x ", foo.byte[i]);
} printf("\n");
is going to try to de-reference the value of targetValue, which would probably give you a segfault.
The thing is, since you declared targetValue as an int, it will always be sizeof(int) bytes long. There is no reason to dynamically allocate it.
You can change your struct to:
union {
unsigned int integer;
unsigned char byte[sizeof(int)];
} foo;
I assume what you are trying to do is figure out the minimum number of bytes to encode the value of targetValue, and create a union of exactly that size.
Another thing to understand about unions is that they always take the amount of space of their largest member, so even if do dynamically allocate the union, you would have to make it at least sizeof(int) long, otherwise you would corrupt adjacent memory whenever you wrote to the int.
Probably you need to rethink what you are trying to do and approach it from a different angle.

Related

Convert integer to byte array produces unexepected results

OK...this seems like a fairly easy problem but I can't figure out what is going on here. I have the following code to convert an integer to a byte array and test the output:
#include <stdio.h>
void int2bytearray(char *byte_array, int size, int num)
{
for (int i = 0; i < size; i++)
{
byte_array[i] = (num >> 8*i) & 0xFF;
}
}
int main()
{
int test_int = 657850;
int size = sizeof(int);
printf("Size is %d\n", size);
printf("Size of char is %d\n", (int)sizeof(char));
char test_array[size];
printf("Size of first entry %d\n", (int)sizeof(test_array[0]));
int2bytearray(test_array, size, test_int);
for (int i=0; i < size; i++)
{
printf("%#02x", test_array[i]);
}
printf("\nFirst byte is %#.2X", test_array[0]);
return 0;
}
I expect main to return an array of bytes, but the first "byte" appears to be a 32 bit integer.
Unfortunately, I get the following output:
Size is 4
Size of char is 1
Size of first entry 1
0xffffffba0x90xa00
First byte is 0XFFFFFFBA
Can someone tell me why this first byte is printing out as 0XFFFFFFBA? Why is it a 32-bit integer and not a byte as defined?
The problem is related both to the type being used and how you're printing the values.
The first element in the array has value 0xBA which as a signed char is -70 in decimal. When this value is passed to printf it is converted to type int, so now you have a 32 bit value of -70 whose representation is 0XFFFFFFBA you then print it using %X it which prints an unsigned int in hex.
There are two ways to fix this.
First, change the type of test_array to unsigned char. Then the values stored will be positive and print correctly. The other option is to use %hhX as the format specifier which states to print the value as an unsigned char which will print the proper number of digits.

Convert serial port data to float in C with union

I'm using a C program on Linux to read data from a serial port.
The data to read comes from Code Composer Studio from the line: UART_writePolling(uartHandle, (uint8_t*) &value, sizeof(float));
value is the float I want to read in C, where value = 1.5.
When I read in the data from the serial port, in C, into a buffer and print with printf("%u\n", (int)buffer[i]);
I get value to be:
0
0
4294967232
63
and when I insert buffer[i] into a.array and print with
printf("%d\n", a.array[i]);
I get value to be:
0
0
-64
63
I've also tried using unions:
unsigned int value = 0;
for (int j = 3; j >= 0; j--){
//value <<= 8;
value = value + (int)a.array[i+8+j];
}
printf("value: %u\n", value);
data.u = value;
printf("(float): %f\n", data.f);
which doesn't give the correct answer.
How can I use union to get the correct data as a float?
Do I need to use <<?
EDIT: better idea of the code
//headers
typedef struct {
int *array;
size_t used;
size_t size;
} Array;
void initArray(Array *a, size_t initialSize) {
a->array = (int *)malloc(initialSize * sizeof(int));
a->used = 0;
a->size = initialSize;
}
... //more functions/code to resize array and free the memory later
union Data {
float f;
unsigned int u;
};
int main(){
union Data data;
//open serial port code
char buffer[1]; /* Buffer to store the data received,
reading one at a time */
Array a;
initArray(&a, 5); /* initialise an array to store the read data
that is read into buffer*/
//while loop to read in data for some amount of time/data
int b_read = 0;
b_read = read(fd, &buffer, sizeof(buffer));
for (int i=0; i<b_read; i++){
printf("%u\n", (int)buffer[i]);
// how the first set of values above were printed
insertArray(&a, buffer[i]);
// also adding the values read to buffer into array a
}
//end while
// close the port
for(int i=0; i<no. of elements in array a; i++){
printf("%d\n", a.array[i]);
// how the second set of results were printed
}
//below is an attempt at using union and <<:
unsigned int value = 0;
for (int j = 3; j >= 0; j--){
//value <<= 8;
value = value + (int)a.array[i+8+j]; //index used is particular to my code, where value is in a specific place in the array
}
printf("value: %u\n", value);
data.u = value;
printf("(float): %f\n", data.f);
//these printfs don't give a reasonable answer
// free memory
return 0;
}
Once the bytes are in buffer starting at offset i, you can reinterpret the bytes as a float with:
float f;
memcpy(&f, buffer+i, sizeof f);
To use a union, you could use:
union { uint32_t u; float f; } x;
x.u = value;
float f = x.f;
However, this requires that value contain all 32 bits that represent the float. When you attempted to construct the value with:
//value <<= 8;
value = value + (int)a.array[i+8+j];
There are two issues. First, value <<= 8 is needed. I presume you tried it first and did not get a correct answer, so you commented it out. However, it is required. Second, this code to insert the bytes one-by-one into value is order-dependent. Once the shift is restored, it will insert greater-addressed bytes into less-significant bits of value. Systems generally arrange bytes in objects in one of two orders: More significant bytes in lower addresses or more significant bytes in greater addresses. We do not know which order your system uses, so we do not know whether your code to insert the greater-addressed bytes in less significant bytes is correct.
Note: The above assumes that the bytes are read and written in the same order, or that issues of endianness have already been handled in other code.
You use printf with %u but cast into a int. So maybe it's not surprising to have this behavior since 2^32 = 4294967296, and 4294967296 - 64 (your second printf result) = 4294967232 (your first printf result).
Just cast into "unsigned" if you use "%u" or cast into "int" if you use "%d".

issue convert double range number to binary

I have a problem to convert integer type's double rage number to binary as the below,
void intToBin(int digit) {
int b;
int k = 0;
char *bits;
int i;
bits= (char *) malloc(sizeof(char));
while (digit) {
b = digit % 2;
digit = digit / 2;
bits[k] = b;
k++;
}
for ( i = k - 1; i >= 0; i--) {
printf("%d", bits[i]);
}
}
But as you can see the that function's arguments input is integer.
I came across the error when I tried with intToBin(10329216702565230)
because 10329216702565230 is over integer range.
How can I extend what that have integer type's double rage number to binary ?
update
I've updated the below code
void intToBin(uint64_t digit) {
int b;
int k = 0;
char *bits;
int i;
bits = malloc(sizeof digit * 64);
while (digit) {
b = digit % 2;
digit = digit / 2;
bits[k] = b;
k++;
}
for ( i = k - 1; i >= 0; i--) {
printf("%d", bits[i]);
}
}
But I didn't get it what should I do to get the 2's complement ?
m
dmnngn
Solution is to use type which supports that range of numbers.
Use unsigned long long or uint64_t(assuming you are passing non negative integers, otherwise use long long or int64_t). Then you call the function like this Edited to add int64_t to uint64_t from the comment posted. unsigned long long is 64 bits atleast - can even be wider. With OP's comment of getting 64 bits output - better to use (u)int64_t
intToBin(10329216702565230U)
In case you want to use negative numbers use long long.Call it like this
intToBin(10329216702565230L).
You didn't allocate enough memory - you were accessing memory that you haven't allocated, resulting in Undefined behavior. You have allocated 1 char first and then you didn't allocate. You can solve this by reallocating - reallocate memory inside the loop (reallocate 1 char at a time inside loop). And then use it. Instead of calling realloc multiple times why don't you allocate memory for 64 chars and then use it to store the result. And in the end, the left over space can be freed with another realloc call.
You don't need to cast the return value of malloc (void* to char* conversion is done implicitly).
You didn't check the return value of malloc. malloc may return NULL and in that case you have to handle that separately. For example:-
#define NBITS 64
...
...
bits = malloc(NBITS);
if( bits == NULL ){
perror("malloc failed");
exit(EXIT_FAILURE);
}
Note: The 64 magic number is coming introduced with the thought that unsigned long long is 64 bits atleast. So while converting we will be using that in case the number of bits exceeds 64 we will reallocate. A better choice is to use what chux said - sizeof digit * CHAR_BIT.
Also
bits[k] = b+'0';
We are putting the ascii value and then you can print it like this
printf("%c", bits[i]);
You forgot to free the allocated memory. Without freeing it (free(bits)), you have memory leak.
Davic C. Rankins comment
void intToBin(int digit)
{
int b;
int k = 0;
char *bits;
int i;
bits= (char *) malloc(sizeof(char));
while (digit) {
b = digit % 2;
digit = digit / 2;
bits[k] = b;
k++;
}
for ( i = k - 1; i >= 0; i--) {
printf("%d", bits[i]);
}
}
The answer is simple,
Replace int with int64_t to use 64 bits instead of 32.
Please try it and let us know
Replace int with int64_t to use 64 bits instead of 32.

C Program: square brackets when printing 2D character array

I am having a confusing issue -- for me at least, this may be very simple and I am missing something. I am trying to initialize a 2D array of variable size, The array is a part of a struct. I am having no issue allocating memory for the array but when I try to assign characters to the array, or print them I receive unexpected results =/
My last attempt has shown that no matter when character I assign to the array, when I print a '[' will be printed... that was the first time I was actually able to print anything. My previous attempts returned seg faults. Here is the code, what am I missing. Thank you.
typedef struct world_map {
char ** map_array;
int X, Y;
} MAP_s;
//
MAP_s * map;
int init_map_array(void) {
int i; // temp
map = malloc(sizeof (MAP_s));
map->X = 20; // Columns
map->Y = 10; // Rows
//
map->map_array = malloc(map->Y * (sizeof (char *)));
//
if (map->map_array == 0) {
printf("ERROR: out of memory!");
return -1;
} else {
for (i = 0; i < map->Y; ++i) {
map->map_array[i] = malloc(map->X * sizeof (char));
if (map->map_array[i] == 0) {
printf("ERROR: out of memory!");
return -1;
}
}
}
int curr_pos_x, curr_pos_y;
int limit_x = map->X;
int limit_y = map->Y;
//
for (curr_pos_y = 0; curr_pos_y < limit_y; ++curr_pos_y) {
for (curr_pos_x = 0; curr_pos_x < limit_x; ++curr_pos_x) {
map->map_array[curr_pos_y][curr_pos_x] = "#";
}
}
return 1;
}
int draw_map(void) {
int curr_pos_x, curr_pos_y;
int limit_x = map->X;
int limit_y = map->Y;
//
for (curr_pos_y = 0; curr_pos_y < limit_y; ++curr_pos_y) {
for (curr_pos_x = 0; curr_pos_x < limit_x; ++curr_pos_x) {
printf("%c", map->map_array[curr_pos_y][curr_pos_x]);
}
printf("\n");
}
}
int main(void) {
init_map_array();
draw_map();
//
printf("STRUCT: %i\n", sizeof (map));
printf("X: %i\n", sizeof (map->X));
printf("Y: %i\n", sizeof (map->Y));
printf("ARRAY: %i\n", sizeof (map->map_array));
return (EXIT_SUCCESS);
}
As a side note, those 4 printf at the end all return "4", I'm fairly certain that if a struct contains 3 elements which are each 4 bytes that it should be larger than 4 bytes itself...
Seems to work fine for me, but there is one error (somehow my GCC was "smart" enough to handle it but it's still an error):
map->map_array[curr_pos_y][curr_pos_x] = "#";
That assigns a char * (pointer to a char in the data segment) instead of a char which will of course result in weird characters. Change "#" to '#' and it should work.
Also, regarding your printfs at the end: they should look like this:
printf("STRUCT*: %lu\n", sizeof (map)); // Prints sizeof(MAP_s *) == sizeof(void *) == 4;
printf("STRUCT: %lu\n", sizeof (*map)); // Prints sizeof(MAP_s) == 16 on my system (iMac w/ Mac OS X),
// alignment and native pointer size might give you different values.
printf("X: %d\n", map->X); // Prints the X dimension. No sizeof.
printf("Y: %d\n", map->Y); // Prints the Y dimension. No sizeof.
You can't print the size of the map->map_array as sizeof works at compile-time and can only return constants for types where the size is known at compile-time. The only way to determine the size of map_array is to save the size argument you gave to malloc in a variable.
Try
map->map_array[curr_pos_y][curr_pos_x] = '#';
instead of
map->map_array[curr_pos_y][curr_pos_x] = "#";
map->map_array[curr_pos_y][curr_pos_x] is of type char and you are assigning a string constant to it.

Problems writing the memset function

I am writing the memset function and my code is below, I am having a problem
void* memsetFun(void* pointer, int c, int size) {
if ( pointer != NULL && size > 0 ) {
unsigned char* pChar = pointer;
int i = 0;
for ( i = 0; i < size; ++i) {
unsigned char temp = (unsigned char) c;
*pChar++ = temp; // or pChar[i] = temp (they both don't work)
}
}
return pointer;
}
I also tried pChar[i] = the value we want and still not working. It gives me some trash numbers that do not make any sense.
And I am calling it:
memsetFun(address, num, size);
printf("value at %p is %d\n", address, *((int*) address));
Where I call the address (I just input the address)
For example, if you to print the chars ( c ) it prints like a weird char that looks like ( for the value 4 )
0 0
0 4
Your code looks fine to me and several people here have commented that it works on their system.
So the obvious thing to do is to debug it - that's a skill that will come in handy quite a bit in future :-) You should learn it now.
What does the following code output when you run it?
void* memsetFun(void* pointer, int c, int size) {
printf("A %x %d %d\n", pointer, c, size);
if ( pointer != NULL && size > 0 ) {
printf("B\n");
unsigned char* pChar = pointer;
int i = 0;
for ( i = 0; i < size; ++i) {
printf("C %d (%d)", i, *pChar);
unsigned char temp = (unsigned char) c;
*pChar++ = temp; // or pChar[i] = temp (they both don't work)
printf(" -> (%d)", i, *(pChar-1));
}
}
printf("D\n");
return pointer;
}
From the output, it should be clear what paths the code is taking and what your parameters are (which will greatly assist the debugging process).
Update:
If you're filling your memory block with anything other than zeros and using this:
printf("value at %p is %d\n", address, *((int*) address));
to print it out, you will get strange results.
You're basically asking for a number of those bytes to be interpreted as an integer. So, for example, if you filled it with 0x02 bytes and you have a 4-byte integer type, you will get the integer 0x02020202 (33686018), not 0x02 as you may expect. If you want to see what the first character value is, use:
printf("value at %p is %d\n", address, *((char*) address));
And based on your latest question update:
For example, if you to print the chars ( c ) it prints like a weird char that looks like ( for the value 4 )
0 0
0 4
If that's a single character and you're printing it as a character, there's probably nothing wrong at all. Many output streams will give you that for a control character (CTRL-D in this case, ASCII code 4). If you instead filled it with ASCII code 0x30 (48), you would see the character '0' or ASCII 0x41 (65) would give you 'A'.
As pointed out already, your function works as it should. Here is a complete example:
#include <assert.h>
#include <string.h>
void* memsetFun(void* pointer, int c, int size) {
if ( pointer != NULL && size > 0 ) {
unsigned char* pChar = pointer;
int i = 0;
for ( i = 0; i < size; ++i) {
unsigned char temp = (unsigned char) c;
*pChar++ = temp; // or pChar[i] = temp (they both don't work)
}
}
return pointer;
}
int main() {
// Your memset
char a[10];
memsetFun(a, 'A', sizeof(a));
// Uses system memset for verification
char b[10];
memset(b, 'A', sizeof(b));
assert(sizeof(a) == sizeof(b));
assert(memcmp(a, b, sizeof(b)) == 0);
return 0;
}
return p; prevents this from compiling: p is not defined.
A minor efficiency issue—in practice it would have little effect, since any good compiler would rearrange it, but coding perfectionists wouldn't allow it to remain—the assignment to temp is inside the loop, but it is the same assignment every time. That is, the assignment to temp can be moved before the loop.
You return p, which isn't defined/doesn't point to anything in particular. Maybe you meant pointer?
The code is logically correct. With the p => pointer change it works correctly.
Clarify how exactly it is "not working". Perhaps you are not understanding what it is supposed to do?
You are probably getting trash numbers because you are casting from an int (4 bytes) to an unsigned char (1 byte), so if c > 255 or < 0 you won't be memsetting the values you are expecting to be.
I ran a test if your program setting the memory of an int vector of 5 elements setting with the value 0x01.
The problem here is that you are iterating in a vector of int for example (which is 4 bytes) but iterating over it using char pointer arithmetic (1 byte). If you want to memset 0x01 for example you will write this number per value in the vector: 00000001000000010000000100000001
which gives me the same value using the original memset.
Your function, as is, works for me.
I suppose you're calling it wrong. I call it like this
char a[100];
memsetFun(a, 0, sizeof a);
int b[100];
memsetFun(b, 0, sizeof b);
How are you calling your memsetFun()?
Edit
With
int b[100];
memsetFun(b, 9, sizeof b);
as an int is made up of 4 bytes (on my system) each value will be set to 0x09090909 or 151587081.
That is exactly what it's supposed to do. Your function is working perfectly fine. The value "0x4" is not the ASCII character '4'.

Resources