bluey31
bluey31

Reputation: 180

Passing the destination memory address as a uint32_t to memcpy throws warning

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

Answers (2)

Ryan Haining
Ryan Haining

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

zwol
zwol

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

Related Questions