Reputation: 180
I am currently writing a kernel which involves a lot of arithmetic on memory addresses and am getting the following infamous warning on memcpy:
warning: passing argument 1 of 'memcpy' makes pointer from integer without a cast
memcpy(dest, &bf, 16*sizeof(uint32_t));
The example of where the warning is thrown is when I do the following
uint32_t bf[16];
uint32_t shmem = (uint32_t)&tos_shared;
uint32_t dest = shmem - 16*sizeof(uint32_t);
memcpy(dest, &bf, 16*sizeof(uint32_t));
Where &tos_shared (0x700347a8)
is the top of stack memory address. I cast it to a uint32_t (1879263144)
so I can do the arithmetic and get my desired destination address, dest (1879262952)
.
How can I convert dest
to a pointer but retain the destination address so memcpy doesn't complain and bf is put in the same place? It's worth mentioning this code functions fine...
Upvotes: 1
Views: 1906
Reputation: 36882
You would get the right result by using a char*
to &tos_shared
. You can also use sizeof bf
to simplify a bit.
uint32_t bf[16];
char* shmem = (char*)&tos_shared;
void* dest = shmem - sizeof bf; // sizeof bf == sizeof(uint32_t) * 16
memcpy(dest, &bf, sizeof bf);
If you ever do need to store a pointer in an integral type (which you should avoid anyway), the correct type to use is uintptr_t
Upvotes: 3
Reputation: 140748
You need to cast back to a pointer type in order to call memcpy
(either char *
or void *
will work; void *
is more idiomatic here). You also need to do the manual pointer arithmetic using uintptr_t
rather than uint32_t
.
uint32_t bf[16];
uintptr_t shmem = (uintptr_t)&tos_shared;
uintptr_t dest = shmem - 16*sizeof(uint32_t);
memcpy((void *)dest, &bf, 16*sizeof(uint32_t));
This code is not guaranteed to work universally. However, it is implementation-defined whether it works, and since you are writing a kernel, you are (part of) the implementation, so you get to decide that yes, the layout of physical RAM will always be such that it does work.
Depending on your ABI, uint32_t
and uintptr_t
may or may not be the same fundamental type, but you should still use uintptr_t
even if they are, because that's more self-documenting and will make it easier to go 64-bit in the future (assuming that's something you might want).
Upvotes: 4