When doing pointer arithmetic with offsetof, is it well defined behavior to take the address of a struct, add the offset of a member to it, and then dereference that address to get to the underlying member?
Consider the following example:
#include <stddef.h>
#include <stdio.h>
typedef struct {
const char* a;
const char* b;
} A;
int main() {
A test[3] = {
{.a = "Hello", .b = "there."},
{.a = "How are", .b = "you?"},
{.a = "I\'m", .b = "fine."}};
for (size_t i = 0; i < 3; ++i) {
char* ptr = (char*) &test[i];
ptr += offsetof(A, b);
printf("%s\n", *(char**)ptr);
}
}
This should print "there.", "you?" and "fine." on three consecutive lines, which it currently does with both clang and gcc, as you can verify yourself on wandbox. However, I am unsure whether any of these pointer casts and arithmetic violate some rule which would cause the behavior to become undefined.
As far as I can tell, it is well-defined behavior. But only because you access the data through a char type. If you had used some other pointer type to access the struct, it would have been a "strict aliasing violation".
Strictly speaking, it is not well-defined to access an array out-of-bounds, but it is well-defined to use a character type pointer to grab any byte out of a struct. By using offsetof you guarantee that this byte is not a padding byte (which could have meant that you would get an indeterminate value).
Note however, that casting away the const qualifier does result in poorly-defined behavior.
EDIT
Similarly, the cast (char**)ptr is an invalid pointer conversion - this alone is undefined behavior as it violates strict aliasing. The variable ptr itself was declared as a char*, so you can't lie to the compiler and say "hey, this is actually a char**", because it is not. This is regardless of what ptr points at.
I believe that the correct code with no poorly-defined behavior would be this:
#include <stddef.h>
#include <stdio.h>
#include <string.h>
typedef struct {
const char* a;
const char* b;
} A;
int main() {
A test[3] = {
{.a = "Hello", .b = "there."},
{.a = "How are", .b = "you?"},
{.a = "I\'m", .b = "fine."}};
for (size_t i = 0; i < 3; ++i) {
const char* ptr = (const char*) &test[i];
ptr += offsetof(A, b);
/* Extract the const char* from the address that ptr points at,
and store it inside ptr itself: */
memmove(&ptr, ptr, sizeof(const char*));
printf("%s\n", ptr);
}
}
Given
struct foo {int x, y;} s;
void write_int(int *p, int value) { *p = value; }
nothing in the Standard would distinguish between:
write_int(&s.y, 12); //Just to get 6 characters
and
write_int((int*)(((char*)&s)+offsetof(struct foo,y)), 12);
The Standard could be read in such a way as to imply that both of the above violate the lvalue-type rules since it does not specify that the stored value of a structure can be accessed using an lvalue of a member type, requiring that code wanting to access as structure member be written as:
void write_int(int *p, int value) { memcpy(p, value, sizeof value); }
I personally think that's preposterous; if &s.y can't be used to access an
lvalue of type int, why does the & operator yield an int*?
On the other hand, I also don't think it matters what the Standard says. Neither clang nor gcc can be relied upon to correctly handle code that does anything "interesting" with pointers, even in cases that are unambiguously defined by the Standard, except when invoked with -fno-strict-aliasing. Compilers that make any bona fide effort to avoid any incorrect aliasing "optimizations" in cases which would be defined under at least some plausible readings of the Standard will have no trouble handling code that uses offsetof in cases where all accesses that will be done using the pointer (or other pointers derived from it) precede the next access to the object via other means.
Related
I'm interested in the technique used by Sean Barrett to make a dynamic array in C for any type. Comments in the current version claims the code is safe to use with strict-aliasing optimizations:
https://github.com/nothings/stb/blob/master/stb_ds.h#L332
You use it like:
int *array = NULL;
arrput(array, 2);
arrput(array, 3);
The allocation it does holds both the array data + a header struct:
typedef struct
{
size_t length;
size_t capacity;
void * hash_table;
ptrdiff_t temp;
} stbds_array_header;
The macros/functions all take a void* to the array and access the header by casting the void* array and moving back one:
#define stbds_header(t) ((stbds_array_header *) (t) - 1)
I'm sure Sean Barrett is far more knowledgeable than the average programmer. I'm just having trouble following how this type of code is not undefined behavior because of the strict aliasing rules in modern C. If this does avoid problems I'd love to understand why it does so I can incorporate it myself (maybe with a few less macros).
Lets follow the expansions of arrput in https://github.com/nothings/stb/blob/master/stb_ds.h :
#define STBDS_REALLOC(c,p,s) realloc(p,s)
#define arrput stbds_arrput
#define stbds_header(t) ((stbds_array_header *) (t) - 1)
#define stbds_arrput(a,v) (stbds_arrmaybegrow(a,1), (a)[stbds_header(a)->length++] = (v))
#define stbds_arrmaybegrow(a,n) ((!(a) || stbds_header(a)->length + (n) > stbds_header(a)->capacity) \
? (stbds_arrgrow(a,n,0),0) : 0)
#define stbds_arrgrow(a,b,c) ((a) = stbds_arrgrowf_wrapper((a), sizeof *(a), (b), (c)))
#define stbds_arrgrowf_wrapper stbds_arrgrowf
void *stbds_arrgrowf(void *a, size_t elemsize, size_t addlen, size_t min_cap)
{
...
b = STBDS_REALLOC(NULL, (a) ? stbds_header(a) : 0, elemsize * min_cap + sizeof(stbds_array_header));
//if (num_prev < 65536) prev_allocs[num_prev++] = (int *) (char *) b;
b = (char *) b + sizeof(stbds_array_header);
if (a == NULL) {
stbds_header(b)->length = 0;
stbds_header(b)->hash_table = 0;
stbds_header(b)->temp = 0;
} else {
STBDS_STATS(++stbds_array_grow);
}
stbds_header(b)->capacity = min_cap;
return b;
}
how this type of code is not undefined behavior because of the strict aliasing
Strict aliasing is about accessing data that has different effective type than data stored there. I would argue that the data stored in the memory region pointed to by stbds_header(array) has the effective type of the stbds_array_header structure, so accessing it is fine. The structure members are allocated by realloc and initialized one by one inside stbds_arrgrowf by stbds_header(b)->length = 0; lines.
how this type of code is not undefined behavior
I think the pointer arithmetic is fine. You can say that the result of realloc points to an array of one stbds_array_header structure. In other words, when doing the first stbds_header(b)->length = inside stbds_arrgrowf function the memory returned by realloc "becomes" an array of one element of stbds_array_header structures, as If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access from https://port70.net/~nsz/c/c11/n1570.html#6.5p6 .
int *array is assigned inside stbds_arrgrow to point to "one past the last element of an array" of one stbds_array_header structure. (Well, this is also the same place where an int array starts). ((stbds_array_header *) (array) - 1) calculates the address of the last array element by subtracting one from "one past the last element of an array". I would rewrite it as (char *)(void *)t - sizeof(stbds_array_header) anyway, as (stbds_array_header *) (array) sounds like it would generate a compiler warning.
Assigning to int *array in expansion of stbds_arrgrow a pointer to (char *)result_of_realloc + sizeof(stbds_array_header) may very theoretically potentially be not properly aligned to int array type, breaking If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined from https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7 . This is very theoretical, as stbds_array_header structure has size_t and void * and ptrdiff_t members, in any normal architecture it will have good alignment to access int (or any other normal type) after it.
I have only inspected the code in expansions of arrput. This is a 2000 lines of code, there may be other undefined behavior anywhere.
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 am working on a set of C code to optimize it. I came across a warning while fixing a broken code.
The environment is Linux, C99, compiling with -Wall -O2 flags.
Initially a struct text is defined like this:
struct text {
char count[2];
char head[5];
char textdata[5];
}
The code is to return pointer T1 and T2 to expected head and textdata strings:
int main(void) {
struct text *T1;
char *T2;
char data[] = "02abcdeabcde";
T1 = (struct text *)data;
T2 = T1->textdata;
gettextptr((char *)T1, T2);
printf("\nT1 = %s\nT2 = %s\n", (char *)T1, T2);
return (0);
}
void gettextptr(char *T1, char *T2) {
struct text *p;
int count;
p = (struct text *)T1;
count = (p->count[0] - '0') * 10 + (p->count[1] - '0');
while (count--) {
if (memcmp(T2, T1, 2) == 0) {
T1 += 2;
T2 += 2;
}
}
}
This wasn't working as expected. It was expected to return the addresses of first 'c' and last 'e'. Through GDB, I found that, once execution pointer returns from gettextptr() to parent function, it doesn't keep the address of T1 and T2. Then I tried another approach to 'Call by reference' by using double pointer:
int main(void) {
struct text *T1;
char *T2;
char data[] = "02abcdeabcde";
T1 = (struct text *)data;
T2 = T1->textdata;
gettextptr((char **)&T1, &T2);
printf("\nT1 = %s\nT2 = %s\n", (char *)T1, T2);
return (0);
}
void gettextptr(char **T1, char **T2) {
struct text *p;
int count;
p = (struct text *)(*T1);
count = (p->count[0] - '0') * 10 + (p->count[1] - '0');
while (count--) {
if (memcmp(*T2, *T1, 2) == 0) {
*T1 += 2;
*T2 += 2;
}
}
}
When I compile this code with -Wall -O2, I am getting the following GCC warning:
pointer.c: In function ‘main’:
pointer.c:23: warning: dereferencing type-punned pointer will break strict-aliasing rules
So:
Was the code calling by value in first case?
Isn't (char **) permitted for casting while keeping strict aliasing rules?
What am I missing to resolve this warning?
The strict aliasing rule is paragraph 6.5/7 of the Standard. It says basically that you may access an object only through an lvalue of compatible type, possibly with additional qualifiers; the corresponding signed / unsigned type; an array, structure, or union type with one of those among its members, or a character type. The diagnostic you received is saying that your code violates that rule, and it does, multiple times.
You get yourself in trouble very early with:
T1 = (struct text *)data;
That conversion is allowed, though the resulting pointer is not guaranteed to be correctly aligned, but there's not much you can then do with T1 without violating the strict aliasing rule. In particular, if you dereference it with * or -> -- which is in fact the very next thing you do -- then you access a char array as if it were a struct text. That is not allowed, though the reverse would be a different story.
Converting T1 to a char * and accessing the pointed to array through that pointer, as you do later, are some of the few things you may do with it.
gettextexpr() is the same (both versions). It performs the same kind of conversion described above, and dereferences the converted pointer when it accesses p->count. The resulting behavior violates the strict aliasing rule, and is therefore undefined. What GCC is actually complaining about in the second case, however, is probably accessing *T1 as if it were a char *, when it is really a struct text * -- another, separate, strict aliasing violation.
So, in response to your specific questions:
Was the code calling by value in first case?
C has only pass by value, so yes. In the first case, you pass two char pointers by value, which you could then use to modify the caller's char data. In the second case, you pass two char * pointers by value, which you can and do use to modify the caller's char * variables.
Isn't (char **) permitted for casting while keeping strict aliasing rules?
No, absolutely not. Casting to char * (not char **) can allow you to access an object's representation through the resulting pointer, because dereferencing a char * produces an lvalue of character type, but there is no type that can generically be converted from without strict-aliasing implications.
What am I missing to resolve this warning?
You are missing that what you are trying to do is fundamentally disallowed. C does not permit access a char array as if it were a struct text, period. Compilers may nevertheless accept code that does so, but its behavior is undefined.
Resolve the warning by abandoning the cast-to-structure approach, which is providing only a dusting of syntactic sugar, anyway. It's actually simpler and clearer to get rid of all the casting and write:
count = ((*T1)[0] - '0') * 10 + ((*T1)[1] - '0');
It's perhaps clearer still to get rid of all the casting use sscanf:
sscanf(*T1, "%2d", &count);
Note also that even if it were allowed, your specific access pattern seems to make assumptions about the layout of the structure members that are not justified by the language. Implementations may use arbitrary padding between members and after the last member, and your code cannot accommodate that.
typedef struct {
int num;
char arr[64];
} A;
typedef struct {
int num;
char arr[];
} B;
I declared A* a; and then put some data into it. Now I want to cast it to a B*.
A* a;
a->num = 1;
strcpy(a->arr, "Hi");
B* b = (B*)a;
Is this right?
I get a segmentation fault sometimes (not always), and I wonder if this could be the cause of the problem.
I got a segmentation fault even though I didn't try to access to char arr[] after casting.
This defines a pointer variable
A* a;
There is nothing it is cleanly pointing to, the pointer is non-initialised.
This accesses whatever it is pointing to
a->num = 1;
strcpy(a->arr, "Hi");
Without allocating anything to the pointer beforehand (by e.g. using malloc()) this is asking for segfaults as one possible consequence of the undefined behaviour it invokes.
This is an addendum to Yunnosch's answer, which identifies the problem correctly. Let's assume you do it correctly and either write just
A a;
which gives you an object of automatic storage duration when declared inside a function, or you dynamically allocated an instance of A like this:
A *a = malloc(sizeof *a);
if (!a) return -1; // or whatever else to do in case of allocation error
Then, the next thing is your cast:
B* b = (B*)a;
This is not correct, types A and B are not compatible. Here, it will probably work in practice because the struct members are compatible, but beware that strange things can happen because the compiler is allowed to assume a and b point to different objects because their types are not compatible. For more information, read on the topic of what's commonly called the strict aliasing rule.
You should also know that an incomplete array type (without a size) is only allowed as the very last member of a struct. With a definition like yours:
typedef struct {
int num;
char arr[];
} B;
the member arr is allowed to have any size, but it's your responsibility to allocate it correctly. The size of B (sizeof(B)) doesn't include this member. So if you just write
B b;
you can't store anything in b.arr, it has a size of 0. This last member is called a flexible array member and can only be used correctly with dynamic allocation, adding the size manually, like this:
B *b = malloc(sizeof *b + 64);
This gives you an instance *b with an arr of size 64. If the array doesn't have the type char, you must multiply manually with the size of your member type -- it's not necessary for char because sizeof(char) is by definition 1. So if you change the type of your array to something different, e.g. int, you'd write this to allocate it with 64 elements:
B *b = malloc(sizeof *b + 64 * sizeof *(b->arr));
It appears that you are confusing two different topics. In C99/C11 char arr[]; as the last member of a structure is a Flexible Array Member (FAM) and it allows you to allocate for the structure itself and N number of elements for the flexible array. However -- you must allocate storage for it. The FAM provides the benefit of allowing one-allocation and one-free where there would normally be two required. (In C89 a similar implementation went by the name struct hack, but it was slightly different).
For example, B *b = malloc (sizeof *b + 64 * sizeof *b->arr); would allocate storage for b plus 64-characters of storage for b->arr. You could then copy the members of a to b using the proper '.' and '->' syntax.
A short example can illustrate:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NCHAR 64 /* if you need a constant, #define one (or more) */
typedef struct {
int num;
char arr[NCHAR];
} A;
typedef struct {
int num;
char arr[]; /* flexible array member */
} B;
int main (void) {
A a = { 1, "Hi" };
B *b = malloc (sizeof *b + NCHAR * sizeof *b->arr);
if (!b) {
perror ("malloc-b");
return 1;
}
b->num = a.num;
strcpy (b->arr, a.arr);
printf ("b->num: %d\nb->arr: %s\n", b->num, b->arr);
free (b);
return 0;
}
Example Use/Output
$ ./bin/struct_fam
b->num: 1
b->arr: Hi
Look things over and let me know if that helps clear things up. Also let me know if you were asking something different. It is a little unclear exactly where you confusion lies.
Can someone explain why I do not get the value of the variable, but its memory instead?
I need to use void* to point to "unsigned short" values.
As I understand void pointers, their size is unknown and their type is unknown.
Once initialize them however, they are known, right?
Why does my printf statement print the wrong value?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void func(int a, void *res){
res = &a;
printf("res = %d\n", *(int*)res);
int b;
b = * (int *) res;
printf("b =%d\n", b);
}
int main (int argc, char* argv[])
{
//trial 1
int a = 30;
void *res = (int *)a;
func(a, res);
printf("result = %d\n", (int)res);
//trial 2
unsigned short i = 90;
res = &i;
func(i, res);
printf("result = %d\n", (unsigned short)res);
return 0;
}
The output I get:
res = 30
b =30
result = 30
res = 90
b =90
result = 44974
One thing to keep in mind: C does not guarantee that int will be big enough to hold a pointer (including void*). That cast is not a portable thing/good idea. Use %p to printf a pointer.
Likewise, you're doing a "bad cast" here: void* res = (int*) a is telling the compiler: "I am sure that the value of a is a valid int*, so you should treat it as such." Unless you actually know for a fact that there is an int stored at memory address 30, this is wrong.
Fortunately, you immediately overwrite res with the address of the other a. (You have two vars named a and two named res, the ones in main and the ones in func. The ones in func are copies of the value of the one in main, when you call it there.) Generally speaking, overwriting the value of a parameter to a function is "bad form," but it is technically legal. Personally, I recommend declaring all of your functions' parameters as const 99% of the time (e.g. void func (const int a, const void* res))
Then, you cast res to an unsigned short. I don't think anybody's still running on a 16-bit address-space CPU (well, your Apple II, maybe), so that will definitely corrupt the value of res by truncating it.
In general, in C, typecasts are dangerous. You're overruling the compiler's type system, and saying: "look here, Mr Compiler, I'm the programmer, and I know better than you what I have here. So, you just be quiet and make this happen." Casting from a pointer to a non-pointer type is almost universally wrong. Casting between pointer types is more often wrong than not.
I'd suggest checking out some of the "Related" links down this page to find a good overview of how C types an pointers work, in general. Sometimes it takes reading over a few to really get a grasp on how this stuff goes together.
(unsigned short)res
is a cast on a pointer, res is a memory address, by casting it to an unsigned short, you get the address value as an unsigned short instead of hexadecimal value, to be sure that you are going to get a correct value you can print
*(unsigned short*)res
The first cast (unsigned short*)res makes a cast on void* pointer to a pointer on unsigned short. You can then extract the value inside the memory address res is pointing to by dereferencing it using the *
If you have a void pointer ptr that you know points to an int, in order to access to that int write:
int i = *(int*)ptr;
That is, first cast it to a pointer-to-int with cast operator (int*) and then dereference it to get the pointed-to value.
You are casting the pointer directly to a value type, and although the compiler will happily do it, that's not probably what you want.
A void pointer is used in C as a kind of generic pointer. A void pointer variable can be used to contain the address of any variable type. The problem with a void pointer is once you have assigned an address to the pointer, the information about the type of variable is no longer available for the compiler to check against.
In general, void pointers should be avoided since the type of the variable whose address is in the void pointer is no longer available to the compiler. On the other hand, there are cases where a void pointer is very handy. However it is up to the programmer to know the type of variable whose address is in the void pointer variable and to use it properly.
Much of older C source has C style casts between type pointers and void pointers. This is not necessary with modern compilers and should be avoided.
The size of a void pointer variable is known. What is not known is the size of the variable whose pointer is in the void pointer variable. For instance here are some source examples.
// create several different kinds of variables
int iValue;
char aszString[6];
float fValue;
int *pIvalue = &iValue;
void *pVoid = 0;
int iSize = sizeof(*pIvalue); // get size of what int pointer points to, an int
int vSize = sizeof(*pVoid); // compile error, size of what void pointer points to is unknown
int vSizeVar = sizeof(pVoid); // compiles fine size of void pointer is known
pVoid = &iValue; // put the address of iValue into the void pointer variable
pVoid = &aszString[0]; // put the address of char string into the void pointer variable
pVoid = &fValue; // put the address of float into the void pointer variable
pIvalue = &fValue; // compiler error, address of float into int pointer not allowed
One way that void pointers have been used is by having several different types of structs which are provided as an argument for a function, typically some kind of a dispatching function. Since the interface for the function allows for different pointer types, a void pointer must be used in the argument list. Then the type of variable pointed to is determined by either an additional argument or inspecting the variable pointed to. An example of that type of use of a function would be something like the following. In this case we include an indicator as to the type of the struct in the first member of the various permutations of the struct. As long as all structs that are used with this function have as their first member an int indicating the type of struct, this will work.
struct struct_1 {
int iClass; // struct type indicator. must always be first member of struct
int iValue;
};
struct struct_2 {
int iClass; // struct type indicator. must always be first member of struct
float fValue;
};
void func2 (void *pStruct)
{
struct struct_1 *pStruct_1 = pStruct;
struct struct_2 *pStruct_2 = pStruct;
switch (pStruct_1->iClass) // this works because a struct is a kind of template or pattern for a memory location
{
case 1:
// do things with pStruct_1
break;
case 2:
// do things with pStruct_2
break;
default:
break;
}
}
void xfunc (void)
{
struct struct_1 myStruct_1 = {1, 37};
struct struct_2 myStruct_2 = {2, 755.37f};
func2 (&myStruct_1);
func2 (&myStruct_2);
}
Something like the above has a number of software design problems with the coupling and cohesion so unless you have good reasons for using this approach, it is better to rethink your design. However the C programming language allows you to do this.
There are some cases where the void pointer is necessary. For instance the malloc() function which allocates memory returns a void pointer containing the address of the area that has been allocated (or NULL if the allocation failed). The void pointer in this case allows for a single malloc() function that can return the address of memory for any type of variable. The following shows use of malloc() with various variable types.
void yfunc (void)
{
int *pIvalue = malloc(sizeof(int));
char *paszStr = malloc(sizeof(char)*32);
struct struct_1 *pStruct_1 = malloc (sizeof(*pStruct_1));
struct struct_2 *pStruct_2Array = malloc (sizeof(*pStruct_2Array)*21);
pStruct_1->iClass = 1; pStruct_1->iValue = 23;
func2(pStruct_1); // pStruct_1 is already a pointer so address of is not used
{
int i;
for (i = 0; i < 21; i++) {
pStruct_2Array[i].iClass = 2;
pStruct_2Array[i].fValue = 123.33f;
func2 (&pStruct_2Array[i]); // address of particular array element. could also use func2 (pStruct_2Array + i)
}
}
free(pStruct_1);
free(pStruct_2Array); // free the entire array which was allocated with single malloc()
free(pIvalue);
free(paszStr);
}
If what you want to do is pass the variable a by name and use it, try something like:
void func(int* src)
{
printf( "%d\n", *src );
}
If you get a void* from a library function, and you know its actual type, you should immediately store it in a variable of the right type:
int *ap = calloc( 1, sizeof(int) );
There are a few situations in which you must receive a parameter by reference as a void* and then cast it. The one I’ve run into most often in the real world is a thread procedure. So, you might write something like:
#include <stddef.h>
#include <stdio.h>
#include <pthread.h>
void* thread_proc( void* arg )
{
const int a = *(int*)arg;
/** Alternatively, with no explicit casts:
* const int* const p = arg;
* const int a = *p;
*/
printf( "Daughter thread: %d\n", a );
fflush(stdout); /* If more than one thread outputs, should be atomic. */
return NULL;
}
int main(void)
{
int a = 1;
const pthread_t tid = pthread_create( thread_proc, &a );
pthread_join(tid, NULL);
return EXIT_SUCCESS;
}
If you want to live dangerously, you could pass a uintptr_t value cast to void* and cast it back, but beware of trap representations.
printf("result = %d\n", (int)res); is printing the value of res (a pointer) as a number.
Remember that a pointer is an address in memory, so this will print some random looking 32bit number.
If you wanted to print the value stored at that address then you need (int)*res - although the (int) is unnecessary.
edit: if you want to print the value (ie address) of a pointer then you should use %p it's essentially the same but formats it better and understands if the size of an int and a poitner are different on your platform
void *res = (int *)a;
a is a int but not a ptr, maybe it should be:
void *res = &a;
The size of a void pointer is known; it's the size of an address, so the same size as any other pointer. You are freely converting between an integer and a pointer, and that's dangerous. If you mean to take the address of the variable a, you need to convert its address to a void * with (void *)&a.