I have a question about pointer casting for C.
if I have a function with this signature:
uint8_t input_getc(void)
which reads user input from STDIN.
Then I have a pointer
void* buffer
that I store return values from input_getc() in. What would be the proper way to cast this?
//read user input
for(i = 0; i < SIZE; ++i)
{
uint8_t temp = input_getc();
//copy to void* buffer
*(uint8_t *)(buffer + i) = temp //WAY #1
*(buffer + i) = (void *)temp; //WAY #2
}
Are both of these the same?
Thanks
As it is right now, neither of those methods will compile. Since buffer is a void* you can't do arithmetic on it since it has an unknown size.
It's not entirely clear exactly where you are trying to store it. If you're just trying to store the uint8_t into the memory location pointed by buffer with offset i, then it can be done like this:
((uint8_t*)buffer)[i] = temp;
EDIT :
Okay, apparently arithmetic on void* is allowed in C, but not in C++. However, doing so it still considered unsafe behavior.
See this question: Pointer arithmetic for void pointer in C
One way to do this is:
*(((uint8_t*)buffer)+i) = temp;
i am not understanding what do you mean by
copying to `void* buffer`
but if you are doing following thing then way1 is right
int main()
{
int i;
char a[10];
void *buffer;
buffer = &a; // buffer is void* type pointer and its pointing to some buffer then
for(i = 0; i < 10; ++i)
{
uint8_t temp = 65;
//copy to void* buffer
*(uint8_t *)(buffer + i) = temp; //WAY #1
}
printf("\n %s",a);
}
BIG Edit :
IN WAY1
you are adding +i offcet with void * buffer and still whole result is void* then you are typecasting that whole result with uint8_t* then accesing that value so it works
but in way2 you are adding +i offcet with void * buffer still whole result is void* and then you are accesing that value ...which is completely wrong..
you will get warning/error here
warning: dereferencing ‘void *’ pointer
One more Edit :
you can not dereferencing void* pointer but you can do arrithmetic operation with pointer value (not its pointe value)
Related
I'm trying to get struct's address.
I want to get address in an int *, and I want to change address by adding numbers to the int *. I tried several ways, but I can't solve it.
struct num_d {
unsigned char data;
unsigned char pad1;
unsigned char pad2;
unsigned char pad3;
};
struct num_d **m = malloc(sizeof(struct num_d *) * row);
for (int i = 0; i < row; i++)
{
m[i] = malloc(sizeof(struct num_d) * col);
}
How can I get m[0][0]'s address in an int *?
first things first lets typedef your struct, so we can type less and be more clear:
typedef struct num_d num_d;
void pointer
A pointer to void is a "generic" pointer type. A void * can be converted to any other pointer type without an explicit cast. we cannot de-reference a void * or do pointer arithmetic with it; you must convert it to a complete data type pointer first (like int* e.g.) then do the de-refrence or the pointer arithmetic.
Now, malloc() return a void* which points to the allocated heap buffer (if malloc successed in allocation other wise null is the return value).
you code become:
num_d** m = malloc(sizeof(num_d*) * row); /*m is an array of void* pointers (not initialized)*/
for (int i = 0; i < row; i++)
{
m[i] = malloc(sizeof(num_d) * col); /*in each element in m you have a void* that points to struct num_d on the heap*/
}
the sizeof(void*) is the same as sizeof any pointer (except function pointers in some machines/os).
putting it all together
How can I get m[0][0]'s address in an int *?
This is a wrong question! because m is an array of void* to "num_d structs" (holding the num_d heap address).
if you want the start address of the i-th num_d struct in the array m, then, just return the void* in the index i in this array m[i]. and if you want to cast it just cast it (no need actually) just assign it:
int* ptr = m[i];
Take in mind that compilers will warn you, regarding the assignment above (but this assignment is supported and legal) :
warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
or (no need again):
int* ptr = (int*)m[i];
I don't know why you need such behavior, it makes more sense to cast to num_d*
if you want the address of the first data member in the struct num_d, then you must cast to the appropriate data type to get the expected data:
unsigned char data = ((num_d*)m[i])->data;
unsigned char* p_data = &((num_d*)m[i])->data;
You don't need to have the address in an int* in order to be adding to it. The way that [] works, is that it adds to the pointer and dereferences.
You can just add to *(m[0] + 1) to get the second element.
How about:
int *ptr = (int *) m[0];
I have a function
foo(void *buf) {
int i = 0;
unsigned char ptr = get_user_name();
//I want the buffer to hold user name from some position onwards
for(i=0;i<MESSAGE_LTH;i++)
*( (unsigned char*)(buf) + sizeof(some_struct)) ++ = ptr[i];
}
I am getting error: lvalue required as increment operand
I want the buffer to hold the username soon after the struct;
This:
unsigned char ptr = get_user_name();
seems like it should be:
const unsigned char *ptr = get_user_name();
It must be a pointer since you're accessing it like one. It should be const since you're only reading from it.
The copying should be done using memcpy(), and incrementing the pointer afterwards can be done separately:
unsigned char *put = buf; /* Proper type, for pointer arithmetic. */
put += sizeof(some_struct); /* Advance into the buffer. */
memcpy(put, ptr, MESSAGE_LTH); /* Do the copy. */
put += MESSAGE_LTH; /* Advance the pointer to after the name. */
Of course at the end of the above, it's hard to know what to do with put. Perhaps returning it out of the function would make sense, but you don't specify.
That line should be rewritten as
*( (unsigned char*)(buf) + sizeof(some_struct) + i) = ptr[i];
Indeed, an easier-to-understand implementation:
memcpy(buf + sizeof(some_struct), ptr, MESSAGE_LTH);
without the loop.
can someone help with this piece of code? I leaved out check of allocations to keep it brief.
typedef struct {
int x;
int y;
} MYSTRUCT;
void init(MYSTRUCT **p_point);
void plusOne(MYSTRUCT **p_point, int *p_size);
int main()
{
MYSTRUCT *point;
int size = 1;
init(&point);
plusOne(&point, &size);
plusOne(&point, &size);
point[1]->x = 47; // this was the problem
point[1].x = 47; // this is solution
return 0;
}
void init(MYSTRUCT **p_point)
{
*p_point = (MYSTRUCT *) malloc( sizeof(MYSTRUCT) );
}
void plusOne(MYSTRUCT **p_point, int *p_size)
{
(*p_size)++;
*p_point = realloc(*p_point, *p_size * sizeof(MYSTRUCT) ); // also calling to the function is fixed
}
I don't understand why index notation doesn't work after calling to functions.
This is because you are not multiplying the p_size by sizeof(MYSTRUCT) in the call of realloc, and not assigning the results back to p_point:
*p_point = realloc(*p_point, *p_size * sizeof(MYSTRUCT));
Notes:
You do not need to cast the result of malloc or realloc in C.
For consistency, consider passing &size to init, and set it to 1 there.
You have some type confusion going on... Here:
MYSTRUCT *point;
you declare point to be a pointer to a MYSTRUCT structure (or an array of them).
The syntax point[i] is equivalent to *(point + i) - in other words, it already dereferences the pointer after the addition of the appropriate offset, yielding a MYSTRUCT object, not a pointer to one.
The syntax p->x is equivalent to (*p).x. In other words, it also expects p to be a pointer, which it dereferences, and then yields the requested field from the structure.
However, since point[i] is no longer a pointer to a MYSTRUCT, using -> on it is wrong. What you are looking for is point[i].x. You could alternatively use (point + i) -> x, but that's considerably less readable...
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.
I am learning how to write device drivers for linux, and I have a question regarding the use of generic data structures.
I have an assignment, which I have fully functional...so I'm not asking you to do my homework...
This assignment requires a device to be able to enqueue and dequeue elements from a fifo buffer. I made the buffer "generic" so that any element size could be used(and specified at runtime). The source is included below(note this is not the kernel version, but the error is the same)...kernel version requires kmalloc, copy_to/from_user() etc...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct RB_Buffer
{
void* RBData;
unsigned int getindex; //index to remove element
unsigned int putindex; //index to put element at
unsigned int capacity; //max elements buffer holds
unsigned int elemCount; //num elements inserted
unsigned int elemSize; //size of each element
};
void* RB_kcreate(int numElements, unsigned int elementSize);
int putring(struct RB_Buffer *rbptr, void* data);
int getring(struct RB_Buffer *rbptr, void* data);
//Creates a Ring buffer of specified number of elements and element size.
//Returns void* pointer pointing to the RB_Buffer struct. This pointer can
//then be used on putring and getring functions.
void* RB_kcreate(int numElements, unsigned int elementSize)
{
struct RB_Buffer *newBuf = malloc(sizeof(struct RB_Buffer));
if(newBuf == NULL) return 0;
newBuf->RBData = (void*)malloc(elementSize*numElements);//, GFP_KERNEL);
if(newBuf->RBData == NULL)
{
free(newBuf);
return 0;
}
newBuf->capacity = numElements;
newBuf->elemSize = elementSize;
newBuf->getindex = 0;
newBuf->putindex = 0;
newBuf->elemCount = 0;
return newBuf;
}
//puts an element in the buffer. Returns -1 if full, 0 on success
//send data through void* data argument
int putring(struct RB_Buffer *rbptr, void* data)
{
int i = 0;
if ( rbptr->elemCount >= rbptr->capacity )
return -1;
memcpy(&rbptr->RBData[rbptr->putindex * rbptr->elemSize], data, rbptr->elemSize);
rbptr->putindex++;
if (rbptr->putindex >= rbptr->capacity )
rbptr->putindex = 0;
rbptr->elemCount++;
return 0;
}
//removes an element in the buffer. Returns -1 if empty, 0 on success
//data is returned through the data pointer
int getring(struct RB_Buffer *rbptr, void *data)
{
if ( !rbptr->elemCount )
return -1;
rbptr->elemCount--;
memcpy(data, &rbptr->RBData[rbptr->getindex * rbptr->elemSize], rbptr->elemSize);
rbptr->getindex++;
if ( rbptr->getindex >= rbptr->capacity )
rbptr->getindex = 0;
return 0;
}
When I compile this into a kernel module, I get the warnings:
kringbuf_generic.c:53: warning: dereferencing ‘void *’ pointer
kringbuf_generic.c:72: warning: dereferencing ‘void *’ pointer
The error occurs here in putring(in memcpy)
if ( rbptr->elemCount >= rbptr->capacity )
return -1;
memcpy(&rbptr->RBData[rbptr->putindex * rbptr->elemSize], data, rbptr->elemSize);
rbptr->putindex++;
and here in getring, in the memcpy() function
rbptr->elemCount--;
memcpy(data, &rbptr->RBData[rbptr->getindex * rbptr->elemSize], rbptr->elemSize);
rbptr->getindex++;
Obviously since this is a kernel module, it is not really known who will use this, and the fixing the buffer element size would limit the usage of this buffer.
Is there any way to get rid of the warnings? Or is there some fundamental thing I should be doing differently when developing such code?
I think the problem is that this code:
rbptr->RBData[rbptr->getindex * rbptr->elemSize]
Is trying to index into the array pointed at by RBData, which is of type void *. You can't meaningfully make this operation work on a void* pointer, because indexing into an array in C requires you to know the size of the elements in the array, and by definition a void* is an a pointer to elements of an unknown type.
Most compilers let you do this anyway by implicitly casting the void* to a char* and just reading raw byte values. However, it's really not a good idea to do this, since the operation isn't well-defined.
To fix this and silence the warning, consider explicitly typecasting the RBData field to a char* before dereferencing it:
((char *)rbptr->RBData)[rbptr->getindex * rbptr->elemSize]
Or alternatively, just store it as a char* in your struct to avoid having to repeatedly do this typecast.
Hope this helps!