I got this question/assignment on a test yesterday at university. It goes like this:
Give the following structure:
typedef struct _rect {
int width;
int height;
} rect;
How could you scale the width and height members using a cast to int* without explicitly accessing the two members?
So basically, given that struct, how could I do
rect *my_rectangle = malloc(sizeof(rect));
my_rectangle->width = 4;
my_rectangle->height = 6;
// Change this part
my_rectangle->width /= 2;
my_rectangle->height /= 2;
Using a cast to int or int*?
You can scale reliably only the first member:
*((int *) my_rectangle) /= 2;
This does not violate strict aliasing rule, as the Standard explicitely allows to convert pointer to struct object to the pointer of its first member.
C11 §6.7.2.1/15 Structure and union specifiers
Within a structure object, the non-bit-field members and the units in
which bit-fields reside have addresses that increase in the order in
which they are declared. A pointer to a structure object, suitably
converted, points to its initial member (or if that member is a
bit-field, then to the unit in which it resides), and vice versa.
There may be unnamed padding within a structure object, but not at its
beginning.
Assuming that, there is no padding between those members, the second member may be scaled as well, as long as the pointer is of the same (compatible) type as of the member, that is int.
you have starting address of structure, so you can access individual elements
by incrementing address correspondingly. Here since both types are int you can use integer pointer else better to use char pointer.
int *ptr = my_rectangle;
*(ptr) /= 2;
*(ptr+1) /=2;
What they're trying to teach you is how that struct is represented in memory. It has two int members, so it's possible that within memory it could also be viewed as if it were an array of int. So the following could possibly work.
rect *my_rectangle = malloc(sizeof(rect));
my_rectangle->width = 4;
my_rectangle->height = 6;
int *my_array=(int *) my_rectangle;
my_array[0] /= 2;
my_array[1] /= 2;
But it's a really dirty hack and it's entirely possible that a compiler could store your struct in an entirely different way, such that casting it to an int * would not have the desired effect. So not at all recommended if you want to write good clean portable code IMHO.
And if someone were to change the struct, such as by making width & height be float instead of int, the code would probably compile without any issues or warnings and then not work at all how you'd expect.
This task is rather questionable since you can easily end up with invoking poorly defined behavior.
As it happens, we can get away with it since the types of the struct are int, same as the pointer type, and there is an exception in the strict aliasing rule for this.
There's still the issue of padding though, so we would have to ensure that there's no padding present between the integers.
The obscure result is something like this:
// BAD. Don't write code like this!
#include <stddef.h>
#include <stdio.h>
typedef struct
{
int width;
int height;
} rect;
int main (void)
{
rect my_rectangle;
my_rectangle.width = 4;
my_rectangle.height = 6;
int* ptr = (int*)&my_rectangle;
*ptr /= 2;
_Static_assert(offsetof(rect, height) == sizeof(int), "Padding detected.");
ptr++;
*ptr /= 2;
printf("%d %d", my_rectangle.width, my_rectangle.height);
return 0;
}
It is much better practice to use a union instead. We would still have the same padding issue, but wouldn't have to worry about strict aliasing. And the code turns easier to read:
#include <stddef.h>
#include <stdio.h>
typedef union
{
struct
{
int width;
int height;
};
int array[2];
} rect;
int main (void)
{
rect my_rectangle;
my_rectangle.width = 4;
my_rectangle.height = 6;
_Static_assert(offsetof(rect, height) == sizeof(int), "Padding detected.");
my_rectangle.array[0] /= 2;
my_rectangle.array[1] /= 2;
printf("%d %d", my_rectangle.width, my_rectangle.height);
return 0;
}
Related
The code seen below is typical of what is seen in some arena implementations. One such
example can be found here (blog article on an example impl.).
#include<stdio.h>
#include<stdint.h>
#include<stdalign.h>
struct thing {
int a;
int b;
};
char buffer[128];
int main ()
{
uintptr_t p1 = (uintptr_t)buffer;
if (p1 % alignof(struct thing)) return 1;
struct thing *t1 = (void*)buffer;
t1->a = 10;
t1->b = 20;
uintptr_t p2 = (uintptr_t)(buffer + sizeof(struct thing));
if (p2 % alignof(struct thing)) return 1;
struct thing *t2 = (void*)(buffer + sizeof(struct thing));
t2->a = 30;
t2->b = 40;
printf("%d\n",t1->a);
printf("%d\n",t2->a);
return 0;
}
edited code: Made the program return 1 if any pointer lacks proper alignment
Is this an instance of a strict aliasing violation, and ...
Is the only way to place such structures in a buffer and to retrieve a safe to use pointer to the structure to do for example:
struct thing *t1 = memcpy(buffer,&((struct thing){10,20}),sizeof(struct thing));
Is this an instance of a strict aliasing violation
Yes. t1->a etc access the character array through a different type than the "effective type" (char).
Is the only way to place such structures in a buffer and to retrieve a safe to use pointer to the structure to do for example:
You can also create a union of a raw character array and the type you wish to convert to. Example:
typedef union
{
struct thing t;
char buf[128];
} strict_aliasing_hack;
...
strict_aliasing_hack thing t1 = *(strict_aliasing_hack*)buffer;
This is ok because strict_aliasing_hack is "an aggregate or union type that includes one a type compatible with the effective type of the object among its members" (C17 6.5/7).
Naturally, it is best to stay clear of fishy conversions like this entirely. For example the chunk of data returned from malloc has no effective type. So the original code is much better written as:
struct thing *t1 = malloc(128);
And now you can lvalue access *t1 in any way you like.
The problem is that per standard only dynamic memory can be used that way.
Clause 5 Expressions says (ref n1570 for C11):
§6 The effective type of an object for an access to its stored value is the declared type of the object, if any.
If you use:
void * buffer = malloc(128);
then buffer is guaranteed to have an alignment compatible with any standard type and has no declared type.
In that case you can safely store a thing object in buffer without triggering any strict aliasing violation. But in your example code, buffer has a declared type which is char. Whatever the alignment, using a different type is then a strict aliasing violation.
IMO memcpy is always the safest way. It will produce the optimized enough output for the particular platform.
typedef struct thing {
int a;
int b;
}thing;
int geta(const void *buff, const size_t offset)
{
const unsigned char *chbuff = buff;
thing t;
memcpy(&t, chbuff + offset, sizeof(t));
return t.a;
}
int geta1(const void *buff, const size_t offset)
{
const unsigned char *chbuff = buff;
int a;
memcpy(&a, chbuff + offset + offsetof(thing, a), sizeof(a));
return a;
}
https://godbolt.org/z/x8e96ezW9
I'm fairly new to C and I am having trouble working with structs. I have the following code:
typedef struct uint8array {
uint8 len;
uint8 data[];
} uint8array;
int compare_uint8array(uint8array* arr1, uint8array* arr2) {
printf("%i %i\n data: %i, %i\n", arr1->len, arr2->len, arr1->data[0], arr2->data[0]);
if (arr1->len != arr2->len) return 1;
return 0;
}
int compuint8ArrayTest() {
printf("--compuint8ArrayTest--\n");
uint8array arr1;
arr1.len = 2;
arr1.data[0] = 3;
arr1.data[1] = 5;
uint8array arr2;
arr2.len = 4;
arr2.data[0] = 3;
arr2.data[1] = 5;
arr2.data[2] = 7;
arr2.data[3] = 1;
assert(compare_uint8array(&arr1, &arr2) != 0);
}
Now the output of this program is:
--compuint8ArrayTest--
3 4
data: 5, 3
Why are the values not what I initialized them to? What am I missing here?
In your case, uint8 data[]; is a flexible array member. You need to allocate memory to data before you can actually access it.
In your code, you're trying to access invalid memory location, causing undefined behavior.
Quoting C11, chapter §6.7.2.1 (emphasis mine)
As a special case, the last element of a structure with more than one named member may
have an incomplete array type; this is called a flexible array member. In most situations,
the flexible array member is ignored. In particular, the size of the structure is as if the
flexible array member were omitted except that it may have more trailing padding than
the omission would imply. Howev er, when a . (or ->) operator has a left operand that is
(a pointer to) a structure with a flexible array member and the right operand names that
member, it behaves as if that member were replaced with the longest array (with the same
element type) that would not make the structure larger than the object being accessed; the
offset of the array shall remain that of the flexible array member, even if this would differ
from that of the replacement array. If this array would have no elements, it behaves as if
it had one element but the behavior is undefined if any attempt is made to access that
element or to generate a pointer one past it.
A proper usage example can also be found in chapter §6.7.2.1
EXAMPLE 2 After the declaration:
struct s { int n; double d[]; };
the structure struct s has a flexible array member d. A typical way to use this is:
int m = /* some value */;
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
and assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if
p had been declared as:
struct { int n; double d[m]; } *p;
Here is my code
struct ukai { int val[1]; };
struct kai { struct ukai daddr; struct ukai saddr; };
struct kai *k, uk;
uk.saddr.val[0] = 5;
k = &uk;
k->saddr.val[0] = 6;
unsigned int *p = (unsigned int *)malloc(sizeof(unsigned int));
p[0] = k;
int *vp;
vp = ((uint8_t *)p[0] + 4);
printf("%d\n", *vp);
This produces a segmentation fault. However if we replace the last line with printf("%u\n", vp) it gives the address i.e. &(k->saddr.val[0]). However I am unable to print the value present at the address using p[0] but able to print it using k->saddr.val[0].
I have to use p pointer in some way to access value at val[0], I can't use pointer k. I need help here, whether it is even possible or not please let me know.
The code makes no sense:
p[0] = k; converts the value of a pointer k to an int as p is a pointer to int. This is implementation defined and loses information if pointers are larger than type int.
vp = ((uint8_t *)p[0] + 4); converts the int pointed to by p to a pointer to unsigned char and makes vp point to the location 4 bytes beyond this pointer. If pointers are larger than int, this has undefined behavior. Just printing the the value of this bogus pointer might be OK, but dereferencing it has undefined behavior.
printf("%u\n", vp) uses an incorrect format for pointer vp, again this is undefined behavior, although it is unlikely to crash.
The problem is most likely related to the size of pointers and integers: if you compile this code as 64 bits, pointers are larger than ints, so converting one to the other loses information.
Here is a corrected version:
struct ukai { int val[1]; };
struct kai { struct ukai daddr; struct ukai saddr; };
struct kai *k, uk;
uk.saddr.val[0] = 5;
k = &uk;
k->saddr.val[0] = 6;
int **p = malloc(sizeof *p);
p[0] = k;
int *vp = (int *)((uint8_t *)p[0] + sizeof(int));
printf("%d\n", *vp); // should print 6
There is a lot of "dirty" mess with the addresses done here.
Some of this stuff is not recommended or even forbidden from the standard C point of view.
However such pointer/addresses tweaks are commonly used in low level programming (embedded, firmware, etc.) when some compiler implementation details are known to the user. Of course such code is not portable.
Anyway the issue here (after getting more details in the comments section) is that the machine on which this code runs is 64 bits. Thus the pointers are 64 bits width while int or unsigned int is 32 bits width.
So when storing address of k in p[0]
p[0] = k;
while p[0] is of type unsigned int and k is of type pointer to struct kai, the upper 32 bits of the k value are cut off.
To resolve this issue, the best way is to use uintptr_t as this type will alway have the proper width to hold the full address value.
uintptr_t *p = malloc(sizeof(uintptr_t));
Note: uintptr_t is optional, yet common. It is sufficient for a void*, but maybe not a function pointer. For compatible code, proper usage of uintptr_t includes object pointer --> void * --> uintptr_t --> void * --> object pointer.
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
I have an array of arbitrary values, so I have defined it as an array of void pointers, so I can point to any kind of information (like int, character arrays, etc). However, how do I actually assign an int to it?
Take for example these initializations:
void* data[10];
int x = 100;
My intuition would think this, but this gives a compile error:
data[0] = malloc(sizeof(int));
*(data[0]) = x;
Also I thought about using &x, but I would take the address of a local variable, which (to my understanding) would be cleared after exiting from the procedure. So if I have a local variable x, how would I get it into a void pointer type of variable correctly?
*((int*)data[0])=x;
will do it.
You might want to consider using a union. Something like this:
union myvalues
{
int i;
double d;
long l;
};
You could then have
union myvalues *foo[10];
foo[0] = malloc(sizeof(union myvalues));
foo[0]->i = x;
You can also typedef the union. sizeof(union myvalues) will be the maximum of sizeof the members. So if you have int i; and char c[40] in the union, sizeof(union myvalues) will be 40. Writing to i will then overwrite the first 4 characters in c (assuming your ints are 4 bytes).
*((int *)data[0]) = x;
A copy of x will be made, so the fact it is a local variable is not important.
for aliasing reasons its far better to do
mempcy( data[0], &x, sizeof( int ) );
As it happens the compiler will optimise the memcpy call out as sizeof( int ) is a constant value but it won't break various aliasing rules.
Although you can use a cast to make the assignment, it is probably much cleaner to write the code like:
void *data[ 10 ];
int x = 100;
int *p;
p = malloc( sizeof *p );
data[ 0 ] = p;
*p = x;
try this:
data[0] = malloc(sizeof(int));
*((int*)data[0]) = x;
or
(int) (*(data[0])) = x;
don't forget to
free (data[0]);
afterwards.