Maybe I confused people with my example. I was trying to understand a part of the code and simplyfied it. Here is part of the original code (simplyfied again... :)) (see original post below).
uint16_t hal_nrf_read_multibyte_reg(uint8_t *pbuf)
{
uint8_t memtype;
memtype = *(uint8_t*)(&pbuf);
if (memtype == 0x00U)
{
uint8_t data *buf = (uint8_t data *)pbuf;
DOTHIS
}
if (memtype == 0x01U)
{
uint8_t xdata *buf = (uint8_t data *)pbuf;
DOTHAT
}
if (memtype == 0xFEU)
{
uint8_t pdata *buf = (uint8_t data *)pbuf;
DOSOMETHING
}
return SOMETHING;
}
void main()
{
uint8_t payload[3];
hal_nrf_read_multibyte_reg(payload);
while(1) { }
}
So I was wondering, why do they cast pbuf which already is of uint8_t. But I think I've got my answer now.
------------ OLD POST -------------
I'm exploring Nordic Semiconductors nRF24LE1.
If I have the following test code.
void tempF(int *test)
{
int varA;
int varB;
int varC;
varA = *(int*)(&test); // The way it is done in the source code
varB = *(&test);
varC = test;
printf("A: %x\n", varA);
printf("B: %x\n", varB);
printf("C: %x\n", varC);
printf("C1: %x\n", test);
if (test == 0x00)
printf("equals 0x00");
}
int main(void) {
int myArray[3];
tempF(myArray);
return 0;
}
The printfs all give the same reply.
What is the reason for doing it "varA-style"? Examples where it is necessary?
If I use the way in varA I don't get the warning "Warning C260: '=': pointer truncation.
Your three samples are all basically converting a pointer into an int. Technically, this requires a cast in your cases B and C, and your compiler ought to warn you about that. For example:
int varC = (int) test;
With the cast, that is completely valid, but without, not. Nevertheless, your compiler probably produces the same code with or without.
In your example code, however, the type of the expression &test is int **. Casting an expression of that type to int * and dereferencing the result, as is done to assign a value to varA, is intended to have the effect of reinterpreting the bytes of test as those of an int, as with a C++ reinterpret_cast. This does not necessarily produce the same value as converting test directly to an int, as is done to assign a value to varC. They are especially prone to differ if the size of a pointer is not the same as the size of an int on the target system, but they are not required to produce the same result even if the sizes are the same.
On the other hand, applying the * operator directly to the result of the & operator has no net effect, so the value computed for varB will reliably be the same as that computed for varC.
The problem is that any pointer type need not be of same size as an int. The compiler truies to warn you about that fact.
Using (int *)(&test) casts the address of test to be a pointer to int.
Dereferencing this yields an int that happily can be assigned to an int variable. It may still be truncated if pointers need more bits than an int can hold, but you convinvced the compiler that you do know what you are doing and it happens by purpose.
Given that your example varibles are actually int:
int varA;
int varB;
int varC;
Without using the GCC compiler versions 4.4.7 or newer and using stdio.h as noted in comments, the code does not compile, the second two of your statements will error out because of illegal types 'int' and 'pointer to int'
varA = *(int*)(&test); // The way it is done in the source code
varB = *(&test);//error
varC = test; //error
If they were int *
int *varA;
int *varB;
int *varC;
Then the first statement: varA = *(int*)(&test); would error out.
The only way the assignment statements will compile is with the variables declared as follows:
int varA;
int *varB;
int *varC;
varA = *(int*)(&test); // The way it is done in the source code
varB = *(&test);
varC = test;
varA = *(int*)(&test); means interpret the bitwise representation of test as an int, then store it in var.
The cast, (int *), indicates that the bitwise representation of test should be interpreted as an int, while the * operator interprets it as an int.
This is identical to memcpy(&varA, &test, sizeof varA);, if sizeof (int) == sizeof (int *).
Related
I'm trying to make an analogue of sscanf with a specifier %p.
I use this:
int res = ahex2num(buf);
*va_arg(ap, void **) = (void *) res;
It works correctly, i actually get the address i pass, like 0x1A but i am facing this error:
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
In main function:
int main(){
void *a;
readFromStr("0x1A", "%p", &a);
printf("%p", a);
return 0;
}
/*
out: 0x1a
*/
Can I somehow avoid this?
long ahex2num(unsigned char *in){
unsigned char *pin = in;
long out = 0;
while(*pin != 0){
out <<= 4;
out += (*pin < 'A') ? *pin & 0xF : (*pin & 0x7) + 9;
pin++;
}
return out;
}
Apparently pointers, particularly void *, have a different size than int on your system. E.g., pointers may be 64 bits and int may be 32 bits. Implementing %p in a routine like sscanf is a valid reason for converting an integer to void *, but you need to use an integer type that can hold all the bits needed for a pointer. A good type for this may be uintptr_t, declared in <stdint.h>.
You will need to ensure all the code that works with the integers from the scanning, such as ahex2num, can support the necessary width and signedness, including handling potential overflow as desired.
If I had your entire code, I could test it. I assume to remove the warning without using a pragma is as simple as changing your typecast from int to long int.
I solved this problem like this:
long long int res = ahex2num(buf);
I had a bit of a confusion. Below is a very simple example which works:
#include <stdlib.h>
typedef struct
{
unsigned char one: 1;
unsigned char two:1;
unsigned char three: 1;
unsigned char four: 1;
} nibble_bits;
typedef union
{
unsigned char all : 4;
nibble_bits bits;
} nibble;
void initArr(nibble ** arrLoc, unsigned int size)
{
nibble * start = arrLoc[0];
int i =0;
for (i=0; i<size; i++)
{
start[i].all = 0;
}
}
int main()
{
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
initArr(&fourNibbles,4);
}
This compiles fine with no warnings. However, when I change the first line in main:
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
to:
nibble fourNibbles[4];
I get the following:
warning: main.c: In function ‘main’:
main.c:150: warning: passing argument 1 of ‘initArr’ from incompatible pointer type
Upon running, I get a "Bus error 10".
Seems to me like the lines are doing the same thing, except that the malloc is allocating space for the array on the heap and the array declaration is on the stack. But (I thought) either way "fourNibbles" is of type "pointer to nibble", and hence the address of "fourNibbles" would be pointer to pointer to nibble (nibble **).
What am I missing here?
These are not even remotely the same. This
nibble * fourNibbles = (nibble *) malloc(4 * sizeof(nibble));
declares a pointer fourNibbles, while this
nibble fourNibbles[4];
declares an array. Arrays and pointers are two completely different things, which (at object level) have nothing in common. Trying to use them interchangeably in object contexts (like & operator) will only lead to disaster. There lots of information on this topic here on SO (search for "array pointer difference") as well as in this [de-facto standard] C FAQ: http://c-faq.com/aryptr/index.html
There is another thing that draws attention in your code though. Your function
void initArr(nibble ** arrLoc, unsigned int size)
is specifically tailored to the first variant, since it requires a pointer to a pointer as its first argument. It will not work if you attempt to force a pointer to an array to the first argument (which you already had a chance to observe firsthand).
However, the real question here is why your initArr function is written in such a bizarre way. This sequence
void initArr(nibble ** arrLoc, unsigned int size)
{
...
nibble * start = arrLoc[0];
...
start[i].all = 0;
looks rather unusual. Why are you passing a pointer to a pointer instead of an ordinary single-level pointer? E.g. you could simply do
void initArr(nibble *start, unsigned size)
{
unsigned i;
for (i = 0; i < size; ++i)
start[i].all = 0;
}
This version would be called as
initArr(fourNibbles,4); /* note: no `&` operator */
and it would be compatible with both malloc-ed arrays and explicitly declared arrays.
P.S. In C language a better idiom for malloc is
nibble * fourNibbles = malloc(4 * sizeof *fourNibbles);
Note that in this variant type name nibble is mentioned only once.
You are missing that the address of an array has a different type from the pointer that the plain array name becomes when used in an expression.
That is:
int *a1 = ...;
int a2[] = { ... };
some_func(&a1);
some_func(&a2);
cannot be correct unless some_func() expects a void *. The first call passes an int ** — a pointer to pointer to int; the second call passes an int (*)[] — a pointer to array of int. Drop the & from the array.
However, in your code, the problems are more complex. Because the function expects a nibble **, you have problems. What you should be doing is passing a nibble *:
void initArr(nibble *arrLoc, unsigned int size)
{
for (unsigned int i = 0; i < size; i++)
start[i].all = 0;
}
int main(void)
{
nibble *fourNibbles_1 = (nibble *) malloc(4 * sizeof(nibble));
nibble fourNibbles_2[4];
initArr(fourNibbles_1, 4);
initArr(fourNubbles_2, 4);
initArr(&fourNubbles_2[0], 4);
}
Your actual code is doing some really rather weird stuff. How much damage it is doing may depend on how big a pointer is compared to a nibble.
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.
I have a "generic" linked link in C that takes void * data to store the data in a Node.
insertNode(linkedList * list, void *data);
//Storing/retrieving a string works fine;
char *str="test";
insertNode(list, str);
char *getback=(char *)node->data;
//Storing/retrieving an Int results a cast warning
int num=1;
insertNode(list,(void *)num);
int getback=(int)node->data;
This is because int is 32 bit, but void * is 64 bit on x64 machine. What is the best practice to get rid of this error?
Use intptr_t or uintptr_t. They are integers of the same size as a pointer:
#include <stdint.h>
...
intptr_t num = 1;
insertNode(list, (void *) num);
intptr_t getback = (intptr_t) node->data;
Of course, the maximum value that you can store depends on the system, but you can examine it at compile time via INTPTR_MIN and INTPTR_MAX.
Using a void * member to store an integer value isn't very good practice - apart from anything else, there's no guarantee what range of integers are storable in this way. If you want to store either a pointer or an integer in your structure, then what you should be using is a union:
union data {
void *p;
int i;
};
insertNode(linkedList * list, union data data);
// Storing/retrieving a string:
char *str="test";
union data d;
d.p = str;
insertNode(list, d);
char *getback = node->data.p;
// Storing/retrieving an int:
int num = 1;
union data d;
d.i = num;
insertNode(list, d);
int getback = node->data.i;
If you have a compiler that supports C99 constructs, you can make it a little neater by avoiding the local union variable:
// Insert a string
insertNode(list, (union data){ .p = str});
// Insert an int
insertNode(list, (union data){ .i = num});
You can cast it twice: insertNode( list, (void *)(uint64_t) num);
Or you can use "unsigned long" for num instead of int. At least in my experience, sizeof(unsigned long) == sizeof(void *) on both 32 and 64-bit systems. Using uintptr_t may be more correct; it's been a while since I've read the standards.
Are you sure you're doing what you actually want to be doing? In the first example with the string you are passing the pointer to the string literal to insertNode, while in the second example ((void *)num) you are casting the value of the int to a pointer to void. Did you actually want to do this: insertNode(list,(void *)&num);, i.e., passing the reference to the data like you were doing in the first example?
Also as an aside, char *str="test"; makes str point to a string literal, which is read-only. So you really should be doing const char *str="test";. If you wanted a normal (writable) string then char str[] = "test";.
Apologies if you already knew these things and actually wanted to store an int in a void *, I just can't imagine why you would.
Edit: If you actually want generic storage space then a union would be a safe approach. There is absolutely no guarantee that an int will fit in a void * in standard C, even though in most implementations it probably does.
I am a linguist in charge of a C program, so please excuse me if the answer is obvious. I have the following code:
typedef struct array_s {
(...)
void **value;
} array_t;
typedef array_t *array_pt;
array_pt array_new (int size) {
(...)
array->value = (void **)malloc(size*sizeof(void *));
}
void* array_get (array_pt arr, int i) {
return arr->value[i];
}
int main () {
int a = 1234;
int *ptr = &a;
array_pt array = array_new(1);
array_add(array, ptr);
printf("%i\n", (int)array_get(array, 0));
}
It is supposed to provide me with a multi-purpose array (for storing int and char*, if I understood I can only use void), and I guess there are no problems of allocating/freeing. However, I cannot get to cast it into anything useful (i.e., get back the "original" int/char*), and for what I understood it could be because I am in a 64-bit system and the size of a pointer to void is different from the size of a pointer to int/char* (the program is supposed to be used in both 64 and 32 bit systems). I tried using intptr_t and other alternatives, to no luck.
How can I be sure that the code will accept any data type and work on both 32 and 64 bit systems? Thank you.
EDIT:
Sorry for not adding array_add, here it is:
unsigned int array_add (array_pt array, void *ptr) {
(...) // get the next index
// allocate if needed
array->value = (void **)realloc(array->value, array->size*sizeof(void *));
array->value[index] = p;
}
You need to dereference your pointer:
int* temp = array_get(array, 0);
printf("%i\n", *temp);
However, I strongly recommend avoiding this type of approach. You're basically giving away the small amount of help the compiler in C will normally provide - purposefully trying to make non-typesafe arrays.
You need to decide what is it you are trying to do in this case.
(1) If you want to use your void * array to store int values (actual int forcefully converted to void *), then you should add these int values to the array as follows
int a = 1234;
array_pt array = array_new(1);
array_add(array, (void *) a);
and then get them back from array as follows
int a = (int) array_get(array, 0);
printf ("%d\n", a);
or simply
printf ("%d\n", (int) array_get(array, 0)));
That last part is exactly what you did, but you got the first part wrong.
This is a cast-based approach, which is ugly in many ways, but it has certain practical value, and it will work assuming void * is large enough to hold an int. This is the approach that might depend on the properties of 32- and 64-bit systems.
(2) If you want to use your void * array to store int * values (pointers to int), then you should add these int values to the array as follows
int a = 1234;
array_pt array = array_new(1);
array_add(array, &a);
and then get them back from array as follows
int *pa = array_get(array, 0);
printf ("%d\n", *pa);
or simply
printf ("%d\n", *(int *) array_get(array, 0));
This approach is perfectly safe from any portability problems. It has no 32- or 64-bit issues. A void * pointer is guaranteed to safely hold a int * pointer or any other data pointer.
If that was your intent, then you got the first part right and the last part wrong.
Either this or that. You code appears to be a strange mix of the two, which is why it doesn't work, and which is why it is impossible to figure out from your original message which approach you were trying to use.
intmax_t should be an integer type that is 32 bits on 32bits compilers and 64bits on 64bit compilers. You could use %j in your printf statement to print intmax_t. The size of pointers on one system is always the same - independently of them pointing to int, char or void.
printf("%j\n", (intmax_t)array_get(array, 0));