Is there any way I can create two variables that point to the same memory location, so that I can read same memory as int, float, char, any way I like?
I want something like this, only without pointer to f, so that I do not have to dereference every time I read/write to f.
char myArray[100];
float* f = (float *)&myArray[10];
I want to closest thing to C++'s reference in C.
I hope the question makes sense.
Edit: I read stream (4 Kb worth) of bytes from flash memory. This stream contains shorts, ints and floats. I know the locations of these ints and floats in the array. And I want to read/write the aforementioned ints and floats like they are ordinary variables.
This example reads the data into a predefined struct, packed (if necessary). Beware of endian-ness! And of data types: an int on your target might be short on you PC.
#include<stdio.h>
#pragma pack(push, 1)
struct mydata {
int version;
char title[16];
float reading[8];
} mydata;
#pragma pack(pop)
int main(void)
{
FILE *fp;
struct mydata data = {0};
fp = fopen("mydata.bin", "rb");
if (1 != fread(&data, sizeof(data), 1, fp))
{ // error
}
printf("Version = %d\n", data.version);
fclose(fp);
return 0;
}
This is why unions exist.
union u {
char c[4];
float f;
int i; // assuming sizeof(int) = 4 for this example
};
union u cf;
cf.f = 1.;
int i = cf.i;
Beware that the last line is actually incorrect per the C standard, because of strict aliasing. See for example What is the strict aliasing rule? You should always access the binary representation through a char l-value.
Related
I want to get data as a double so after that i send the data as uint8_t array. So I determined 2 steps.Steps;
1-First Step :Double to uint8_t
#include <stdint.h>
#include <stdio.h>
#include <string.h>
void float2Bytes(double val,uint8_t* bytes_array);
int main(void) {
double b=1690.000000;
uint8_t message[1024];
float2Bytes(b,&message[0]);
int ii;
for (ii=0; ii<8; ii++)
printf ("byteS %d is %02x\n", ii, message[ii]);
return 0;
}
void float2Bytes(double val,uint8_t* bytes_array){
// Create union of shared memory space
union {
double double_variable;
uint8_t temp_array[8];
} u;
// Overite bytes of union with float variable
u.double_variable = val;
// Assign bytes to input array
memcpy(bytes_array, u.temp_array, 8);
}
2-Second Step : uint8_t array to Double
Can you advise at the this stages ? How can I do ?
And can you examine at the first stage whether there are errors or not. ?
Thank you.
The union is unnecessary here. Character pointers are special in C and can be used to extract the byte representation of any type. That mean that your current main could be stripped down to:
int main(void) {
double b=1690.000000;
uint8_t* pmessage = (char *) &b; // legal and portable C
int ii;
for (ii=0; ii<sizeof(double); ii++) // portable C
printf ("byteS %d is %02x\n", ii, message[ii]);
return 0;
}
Fro the second step, you need a memcpy operation to copy from a byte array to a different type. Here again no union required for the exact same reason: a char pointer can be used to write the byte representation of any type:
double doubleFromBytes(uint8_t *buffer) {
double result;
// legal and portable C provided buffer contains a valid double representation
memcpy(&result, buffer, sizeof(double))
return result;
}
The only assumption here is that buffer points to an byte array containing the byte representation of a double.
Of course, what you get here is the representation of a double for current architecture. The representation of the same double value can be different on a different architecture (*). It might be a problem if to intend to send the representation to a different machine or to a program compiled with different options.
(*): at least endianness (order of bytes) can be different. Not speaking of exotic (no IEC 60559 floating point) representations where sizeof(double) could be different of 8.
You only need a pointer to do this.
int main(void)
{
double b=1690.000000;
// double to uint8 array
uint8_t* pmessage = (uint8_t*) &b;
int ii;
for (ii=0; ii<sizeof(double); ii++)
printf ("byteS %d is %02x\n", ii, message[ii]);
// uint8 array to ddouble
double c = *((double *)pmessage);
printf ("double %f\n", c);
return 0;
}
Having a little difficulty with pointers. I have to store a float in an array of unsigned ints and be able to pull it out.
I know there is a special way to cast this so I don't reorder the bits, I think this is the correct way to store it when I want to put it into the array:
float f = 5.0;
int newF = (int *) f;
arrayOfInts[0] = *newF
Which seems to successfully store the value in the array.
However, at some point I have to pull the value back out of the array of ints, this is where my confusion comes in (assuming I inputed into the array correctly)
float * f = (float *) arrayOfInts[0]
int result = *f;
however, that gives me the warning: 'cast to pointer from integer of different size'
I can't really think of how to solve that without some sort of long cast.. which doesn't seem right..
I don't want to lose the value or damage the bits.. obviously It will lose decimal point precision.. but I know theirs some way to safety convert back and forth
I have to store a float in an array of unsigned ints and be able to pull it out.
Use a union and unsigned char[]. unsigned char is specified to not have any padding and all bit combinations are valid. This is not always true of many other number types. By overlaying the float with unsigned char[], code can examine each "byte" of the float, one at a time.
union {
float f;
unsigned char uc[sizeof (float)];
} x;
// example usage
x.f = 1.234f;
for (unsigned i = 0; i<sizeof x.uc; i++) {
printf("%u:%u\n", i, 1u*x.uc[i]);
}
Sample output: Yours may vary
0:182
1:243
2:157
3:63
float --> unsigned char[] --> float is always safe.
unsigned char[] --> float --> unsigned char[] is not always safe as a combination of unsigned char[] may not have a valid float value.
Avoid pointer tricks and casting. There are alignment and size issues.
// Poor code
float f = 5.0f;
int newF = *((int *) &f); // Conversion of `float*` to `int*` is not well specified.
Code can also overlay with fixed-width no-padding types like (u)int32_t if they exist (they usually do) and match in size.
#include <stdint.h>
union {
float f;
uint32_t u32;
} x32;
#include <assert.h>
#include <inttypes.h>
// example usage
assert(sizeof x32.f == sizeof x32.u32);
x32.f = 1.234f;
printf("%" PRNu32 "\n", x32.u32);
}
Example output: yours may vary
1067316150
To convert a float to an int
float fval = 123.4f;
int ival = *(int*)&fval;
To convert back
int ival = /* from float */
float fval = *(float*) &ival;
it won't work if float and int are different sizes, but presumably you know that already. The unsigned char union method outlined in other answer for chux is more robust, but over-complicated for what you probably want to do.
I have a buffer where each entry in the buffer is 8 bits in size:
uint8_t Buffer[10] = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};
What I need to do is to create pointers to that array, for example 16 bit and 32 bit pointers. For example:
uint32_t *x;
x = Buffer;
uint32_t *y;
y = Buffer+4;
uint16_t *z;
z = Buffer+8;
Where each variable would then read from the array, for example:
x = 0x78563412
y = 0xf4f3f2f1
z = 0xf6f5
This works completely fine, the problem is that I'm getting warnings about incompatible pointer types. So I was wondering if there is an alternative way of doing this or if I'll just have to live with the warnings? Or am I simply doing this completely the wrong way?
Please note that this code will be executed on a single type of platform where the endianness is always the same and the size of data types is always the same.
You should heed the warnings; what you're doing is undefined behavior. Type aliasing like that is undefined behavior, particularly since there is no guarantee that Buffer has the correct alignment such that it can be accessed as an int/short. If Buffer has the correct alignment, then you can just explicitly cast and it's okay (and the warning will go away).
You have two options:
One, you align the buffer as the larger of the two types. Be careful that your pointer arithmetic doesn't throw off the alignment:
#include <stdalign.h>
alignas(int) unsigned char Buffer[10] = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};
unsigned int *x;
x = (unsigned int*)(Buffer);
unsigned int *y;
y = (unsigned int*)(Buffer+4);
unsigned short *z;
z = (unsigned short*)(Buffer+8);
Two, you create an unsigned int/unsigned short variable and then memcpy the bytes you're interested in into the variable:
unsigned int x;
memcpy(&x, Buffer, 4);
unsigned int y;
memcpy(&y, Buffer + 4, 4);
unsigned short z;
memcpy(&z, Buffer + 8, 2);
The problem with your approach is that it assumes a particular endianness of underlying hardware. Different computers will interpret a sequence of hex bytes
01 23 45 67
as eiter
01234567 or 67452301
Your program may compile and run on both systems, but since the result is hardware-specific, the compiler must warn you of the possibility.
The proper way of forcing a particular endianness is by using an array of integers, convert them using hton and ntoh functions, and set individual bytes either directly by casting a pointer to unsigned char*, or with memcpy.
You might want to use a union
#include <stdint.h>
#include <stdio.h>
typedef union{
uint8_t Buffer[10];
struct{
uint32_t x;
uint32_t y;
uint16_t z;
};
}MYSTRUCT;
int main(){
MYSTRUCT b = {0x12,0x34,0x56,0x78,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6};
printf("x=%#x y=%#x z=%#x\n",b.x,b.y,b.z);
return 0;
}
#include <stdio.h>
typedef struct ss {
int a;
char b;
int c;
} ssa;
int main(){
ssa *ss;
int *c=&ss->a;
char *d=&ss->b;
int *e=&ss->c;
*c=1;
*d=2;
*e=3;
printf("%d=%p %d=%p %d=%p\n",*c,c++,*c,c++,*c,c);
return 0;
}
//prints 1=0x4aaa4333ac68 2=0x4aaa4333ac6c 3=0x4aaa4333ac70
My thinking of how should be the memory structure:
int | char | int
(68 69 6A 6B) (6C) (6D 6E 6F 70)
I'm trying to understand how this code works in memory.
Why int *e starts from 0x...70?
Why c++ (increment) from char (6C) goes 4 bytes more?
Thanks.
First of all, these lines are illegal:
*c=1;
*d=2;
*e=3;
All you have is a pointer to ssa, but you haven't actually allocated any space for the pointed-to object. Thus, these 3 lines are trying to write into unallocated memory, and you have undefined behavior.
Structure layout in memory is such that member fields are in increasing memory addresses, but the compiler is free to place any amount of padding in between for alignment reasons, although 2 structures sharing the same initial elements will have the corresponding members at the same offset. This is one reason that could justify the "gaps" between member addresses.
You should be more careful with how you call printf(). Argument evaluation order is undefined. You are changing the value of c more than once in between 2 sequence points (see Undefined behavior and sequence points). Furthermore, pointer arithmetic is only guaranteed to work correctly when performed with pointers that point to elements of the same array or one past the end.
So, in short: the code has undefined behavior all over the place. Anything can happen. A better approach would have been:
#include <stdio.h>
typedef struct ss {
int a;
char b;
int c;
} ssa;
int main() {
ssa ss = { 0, 0, 0 };
int *c = &ss.a;
char *d = &ss.b;
int *e = &ss.c;
printf("c=%p d=%p e=%p\n", (void *) c, (void *) d, (void *) e);
return 0;
}
The cast to void * is necessary. You will probably see a gap of 3 bytes between the value of d and e, but keep in mind that this is highly platform dependant.
There is often padding inside structures, you cannot assume that each field follows the one before it immediately.
The padding is added by the compiler to make structure member access quick, and sometimes in order to make it possible. Not all processors support unaligned accesses, and even those that do can have performance penalties for such accesses.
You can use offsetof() to figure out where there is padding, but typically you shouldn't care.
Here is the piece of codes where I don't understand
#include "malloc.h"
/*some a type A and type for pointers to A*/
typedef struct a
{
unsigned long x;
} A, *PA;
/*some a type B and type for pointers to B*/
typedef struct b
{
unsigned char length;
/*array of pointers of type A variables*/
PA * x;
} B, *PB;
void test(unsigned char length, PB b)
{
/*we can set length in B correctly*/
b->length=length;
/*we can also allocate memory for the array of pointers*/
b->x=(PA *)malloc(length*sizeof(PA));
/*but we can't set pointers in x*/
while(length!=0)
b->x[length--]=0; /*it just would not work*/
}
int main()
{
B b;
test(4, &b);
return 0;
}
Can anyone elaborate conceptually to me why we can't set pointers in array x in test()?
On the last line of test() you are initializing the location off the end of your array. If your length is 4, then your array is 4 pointers long. b->x[4] is the 5th element of the array, as the 1st is b->x[0]. You need to change your while loop to iterate over values from 0 to length - 1.
If you want to set to null every PA in b->x, then writing --length instead of length-- should do the job.
Obviously trying to figure out where the -- belongs is confusing. You better write:
unsigned i;
for (i = 0; i < length; i++)
b->x[i] = 0;
But in fact, in this case, you could simply use:
memset(b->x, 0, length*sizeof(PA));
Your structure is more complicated by one level of dynamic memory allocation than is usually necessary. You have:
typedef struct a
{
unsigned long x;
...and other members...
} A, *PA;
typedef struct b
{
unsigned char length;
PA * x;
} B, *PB;
The last member of B is a struct a **, which might be needed, but seldom is. You should probably simplify everything by using:
typedef struct a
{
unsigned long x;
} A;
typedef struct b
{
unsigned length;
A *array;
} B;
This rewrite reflects a personal prejudice against typedefs for pointers (so I eliminated PA and PB). I changed the type of length in B to unsigned from unsigned char; using unsigned char saves on space in the design shown, though it might conceivably save space if you kept track of the allocated length separately from the length in use (but even then, I'd probably use unsigned short rather than unsigned char).
And, most importantly, it changes the type of the array so you don't have a separate pointer for each element because the array contains the elements themselves. Now, occasionally, you really do need to handle arrays of pointers. But it is relatively unusual and it definitely complicates the memory management.
The code in your test() function simplifies:
void init_b(unsigned char length, B *b)
{
b->length = length;
b->x = (A *)malloc(length*sizeof(*b->x));
for (int i = 0; i < length; i++)
b->x[i] = 0;
}
int main()
{
B b;
init_b(4, &b);
return 0;
}
Using an idiomatic for loop avoids stepping out of bounds (one of the problems in the original code). The initialization loop for the allocated memory could perhaps be replaced with a memset() operation, or you could use calloc() instead of malloc().
Your original code was setting the pointers in the array of pointers to null; you could not then access any data because there was no data; you had not allocated the space for the actual struct a values, just space for an array of pointers to such values.
Of course, the code should either check whether memory allocation failed or use a cover function for the memory allocator that guarantees never to return if memory allocation fails. It is not safe to assume memory allocation will succeed without a check somewhere. Cover functions for the allocators often go by names such as xmalloc() or emalloc().
Someone else pointed out that malloc.h is non-standard. If you are using the tuning facilities it provides, or the reporting facilities it provides, then malloc.h is fine (but it is not available everywhere so it does limit the portability of your code). However, most people most of the time should just forget about malloc.h and use #include <stdlib.h> instead; using malloc.h is a sign of thinking from the days before the C89 standard, when there was no header that declared malloc() et al, and that is a long time ago.
See also Freeing 2D array of stack; the code there was isomorphic with this code (are you in the same class?). And I recommended and illustrated the same simplification there.
I just added a printf in main to test b.length and b.x[] values and everything's work.
Just added it like that printf("%d, %d %d %d %d", b.length, b.x[0], b.x[1], b.x[2], b.x[3]); before the return.
It gaves 4, 0, 0, 0, 0 which is I think what you expect no? Or it is an algorithmic error
I assume you are trying to zero all of the unsigned longs inside the array of A's pointed to within B.
Is there a precedence issue with the -> and [] operators here?
Try:
(b->x)[length--] = 0;
And maybe change
typedef struct a
{
unsigned long x;
} A, *PA;
to
typedef struct a
{
unsigned long x;
} A;
typedef A * PA;
etc