How to Cast Integer Value to Pointer Address Without Triggering Warnings - c

I have the following variable
uint32_t Value = 0x80
0x80 represents an address in the memory e.g.
// Write 2 at address 0x80
*(uint32_t*)((uint32_t)0x80) = 2;
How can i cast Value to a Pointer, so it points to 0x80?
uint32_t *Pointer = ?? Value;
This:
(uint32_t*)(uint32_t)Value;
returns:
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]

To handle integer to object pointer conversion, use the optional integer uintptr_t or intptr_t types. Function pointers are a separate matter.
The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer C11dr 7.20.1.4 1
uintptr_t
Then convert the void * to the desired type.
#include <stdint.h>
uintptr_t Value = 0x80;
uint32_t *Pointer = (void *) Value;
If 0x80 was not derived from a valid uint32_t *, the result in undefined behavior (UB). Yet it sounds like OP is on a platform with memory mapped data locations.

I will spell it out for you: given
uint32_t Value = 0x80;
you want
*((uint32_t *)(uintptr_t)Value) = 2;
The type uintptr_t, if it exists, is guaranteed to be castable to and from arbitrary pointer types without loss of information. It is not guaranteed to exist, but on platforms where it doesn't exist, what you're trying to do cannot safely be done without a great deal more information.
No other type is officially guaranteed to have this property; however, "cpp plus 1" is correct that size_t usually also does. I would go so far as to say that any ABI for a flat-memory architecture, that doesn't make size_t have this property, was specified incorrectly, but they do exist and sometimes you have to work with them.
It would be better to declare Value with a pointer type in the first place:
uint32_t *const Value = (uint32_t *)(uintptr_t)0x80;
because then you only have to write the casts when you initialize it, not when you use it,
*Value = 2;
and you probably have a bunch of places where you use it. This also avoids a potential problem if it happens that sizeof(uintptr_t) < sizeof(uint32_t), as uint32_t is never involved in the address arithmetic; the compiler may complain if the cast from 0x80 to uintptr_t actually truncates the constant, but that shouldn't ever happen with the real memory addresses you are accessing this way.

Related

Is conversion of a function pointer to a uintptr_t / intptr_t invalid?

Microsoft extensions to C and C++:
To perform the same cast and also maintain ANSI compatibility, you can cast the function pointer
to a uintptr_t before you cast it to a data pointer:
int ( * pfunc ) ();
int *pdata;
pdata = ( int * ) (uintptr_t) pfunc;
Rationale for C, Revision 5.10, April-2003:
Even with an explicit cast, it is invalid to convert a function pointer to an object pointer
or a pointer to void, or vice versa.
C11:
7.20.1.4 Integer types capable of holding object pointers
Does it mean that pdata = ( int * ) (uintptr_t) pfunc; in invalid?
As Steve Summit says:
The C standard is written to assume that pointers to different object types, and especially pointers to function as opposed to object types, might have different representations.
While pdata = ( int * ) pfunc; leads to UB, it seems that pdata = ( int * ) (uintptr_t) pfunc; leads to IB. This is because "Any pointer type may be converted to an integer type" and "An integer may be converted to any pointer type" and uintptr_t is integer type.
Given the definitions
int (*pfunc)();
int *pdata;
, the assignments
pdata = (int *)pfunc;
pdata = (int *)(uintptr_t)pfunc;
are, IMO, equivalent. On a platform where data pointers are of the same size as, or larger than, function pointers, both assignments will work as desired. But on a platform where data pointers are smaller than function pointers, both assignments will inevitably scrape off some of the bits of the function pointer, resulting in a data pointer which can not be converted back to the original function pointer later.
In particular, I believe that both assignments are equivalent despite the presence of the (uintptr_t) cast in the second one. I believe that cast accomplishes precisely nothing.
On a platform where data pointers are smaller than function pointers, and where type uintptr_t is of the same size as data pointers, in the assignment
pdata = (int *)(uintptr_t)pfunc;
, the cast to (uintptr_t) will scrape off some of the bits of pfunc's value.
On a platform where data pointers are smaller than function pointers, and where type uintptr_t is of the same size as function pointers, in the assignment
pdata = (int *)(uintptr_t)pfunc;
, the cast to (int *) will scrape off some of the bits of pfunc's value.
In both cases pdata will end up with only some fraction of pfunc's original value.
(Here I disregard the possibility of architectures with padding bits or the like. On some bizarre, hypothetical platform where function pointers are larger than data pointers, but the extra bits are always 0, both assignments would again work.)
(I've also disregarded the possibility that int * is a different size than void *. I'm not sure whether that would affect the answer, whether a "detour" via void * is more or less un- or necessary when attempting a conversion from int (*)() to int *.)
Casting to uintptr_t only works if this type is defined, which may not be the case on legacy systems using ancient compilers. Note however that uintptr_t must be large enough for any object pointer, especially char * or void *, but may be smaller than function pointers. Such architectures are rare today and Microsoft compilers probably no longer support them, but they were common place in the 16-bit world (MS/DOS, Windows 1, 2 and 3.x) where the medium model had 32-bit segmented code pointers and 16-bit data pointers.
Note also that the C Standard allows for int * and void * to have a different size and representation albeit no Microsoft compiler supports such exotic targets.
On current systems with modern compilers, all data pointers and code pointers have almost always the same size and representation. This is actually a requirement for POSIX compatibility, so the recommendation to use an intermediary cast to (uintptr_t) is valid and effective.
For complete portability, if the goal is to pass a function pointer via an opaque void *, you can always allocate an object of the proper function pointer type, initialize it with pfunc and pass its address:
// setting up the void *
int (*pfunc)();
void *pdata = malloc(sizeof pfunc);
memcpy(pdata, &pfunc, sizeof pfunc);
// using the void *
int (**ppfunc)() = pdata;
(*ppfunc)(); // equivalent to (**ppfunc)();
Is conversion of a function pointer to a uintptr_t / intptr_t invalid?
No. It may be valid. It may be undefined behavior.
Conversion of a function pointer to ìnt* is not defined. Nor to any object pointer. Nor to void *.
pdata = ( int * ) pfunc; is undefined behavior.
Conversion of a function pointer to an integer type is allowed, with restrictions:
Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type. C17dr 6.3.2.3 6
Also integer to a pointer type is allowed.
An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation. C17dr 6.3.2.3 6
void * to integer to void * is defined. Object pointer to/from void* is defined. Then the optional (u)intptr_t types are sufficient for round-trip success. Yet we are concerned about a function pointer. Often enough function pointers are wider than an int *.
Thus converting a function pointer to int * only makes sense through an integer type, wider the better.
VS may recommend through the optional type uintptr_t and is likely sufficient if information is lossless on other platforms. Yet uintmax_t may afford less loss of information, especially in the function pointer to integer step, so I pedantically suggest:
pdata = ( int * ) (uintmax_t) pfunc;
Regardless of the steps taken, code is likely to become implementation specific and deserves guards.
#ifdef this && that
pdata = ( int * ) (uintmax_t) pfunc;
#else
#error TBD code
#endif
Migrating the solution from the question to an answer:
Here is the answer from Microsoft:
Q: How exactly "cast the function pointer to a uintptr_t before you cast it to a data pointer" leads to maintaining "ANSI compatibility"?
A: Without the cast to uintptr_t it’s possible that the code will fail to compile with other compilers, even if they use the same pointer model. For example: https://gcc.godbolt.org/z/9EjTe1s4x - if you add the uintptr_t it compiles without warnings/errors.

access an array from known address

I have a code that I passed a certain place in the memory. This place in the memory is pointing to an array
uint32_t *ps2 = NULL;
uint32_t src_address = 0x1ffffc3;
How can I read the value of the array from this address?
I tried to cast it as follows
*ps2 = (void *)src_address;
but it gives me an error: invalid conversion from ‘void*’ to ‘uint32_t
Regards,
You have two problems:
First of all, the pointer ps2 is a null pointer, it doesn't point anywhere. That means you can't dereference it.
src_address is not a pointer, when it really should be.
All in all there's seems to be some mixup in your understanding of pointers and how they are used.
For it to work, first define ps2 as not a pointer:
uint32_t ps2;
then define src_address as a pointer:
uint32_t *src_address = (uint32_t *) 0x1ffffc3;
and finally dereference src_address like a normal pointer:
ps2 = *src_address;
There is a possible third problem: The address of src_address is not aligned for an uint32_t. On some systems unaligned access is invalid and will lead to hardware exceptions.
This is because you cannot guaranteely convert a pointer type to any integer type. 6.3.2.3(p5) (emp. mine):
Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior
is undefined. The result need not be in the range of values
of any integer type.
The undefined behavior may well be the compile error you see.
There are dedicated types intptr_t, uintptr_t. They are described at 7.20.1.4
The following type designates a signed integer type with the
property that any valid pointer tovoidcan be converted to this
type, then converted back to pointer tovoid,and the result will
compare equal to the original pointer
If your implementation implements the types you should use them. If no there is no any other conforming portable way to convert integers to pointers.
You want to give pointer p2 while (other than NULL).
But here you set this value not to pointer itself, but to memory it points to.
*ps2 = (void *)src_address;
And it points to....well nothing, it's NULL pointer (address 0 is not valid).
By using * you are accessing (or setting) value that pointer points to. So you need to remove * to change the pointer itself.
ps2 = (void *)src_address;
Or even better:
ps2 = (uint32_t*)src_address;
Then to read value from that address:
uint32_t value = *ps;
uint32_t *ps2 = NULL; // Assuming this is where you want your array to point.
uint32_t src_address = 0x1ffffc3; // source array
You can do :
ps2 = (uint32_t *)src_address; // Assuming 32 bit machine
Now to access every element of array, all you have to do is -
*ps2[0], *ps2[1]
ps2[0] will point to src_address + 0.
ps2[1] will point to src_address + 4(As pointer type is uint32_t)

How is this dereferenced?

I'm following a tutorial, where they want to write a particular value (0x0403) to register (at address 0x04000000)
As per my knowledge, this could be done like this,
unsigned int 32 *ptr;
ptr = 0x04000000
*ptr = 0x403
However, they are doing following:
#define REG_DISP *((volatile uint32*)(0x04000000))
#define VIDEOMODE_3 0x0003
#define BGMODE_2 0x0400
int main()
{
REG_DISP = VIDEOMODE_3 | BGMODE_2;
while(1){}
}
Now, I have following questions:
Can we use pointers without declaring any variables?
Why pointer to a pointer is used? Is it because, we cannot do ptr = 0x04000000?
Just a remark. All this can only be implementation defined, because the language itself has no concept of registers living at well known addresses.
The standard just says at 6.3.2.3 Pointers §5 (emphasize mine):
An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
That means that this is valid C, provided the implementation allows it to make sense:
unsigned int *ptr;
ptr = 0x04000000;
*ptr = 0x403;
It just uses a named pointer to access the specific address. It can be done without naming the pointer that way:
* ((unsigned int *) 0x04000000) = 0x403;
Let us see how it works:
(unsigned int *) 0x04000000 converts an unsigned int to a pointer to unsigned int
* ((unsigned int *) 0x04000000) dereferences that pointer
* ((unsigned int *) 0x04000000) = 0x403; assigns a value to the pointed variable
As you want to access a physical register, you need to ask the compiler to immediately write the value instead of keeping it in an internal register which could be allowed per the as if rule. That is the meaning of the volatile qualifier. As it is dedicated to a specific implementation, it is perfectly legal, provided you can be sure that unsigned int has 32 bits in that implementation, to write
volatile unsigned int *ptr;
ptr = 0x04000000;
*ptr = 0x403;
or
* ((volatile unsigned int *) 0x04000000) = 0x403;
Ad. 1: C allows to convert an integral value to a pointer and vice versa. Weather you assign the (intermediate) conversion to a variable or not does not matter. Code part (volatile uint32*)(0x04000000) actually converts integral literal 0x0400000 to a pointer of type uint32*; Note the volatile, which turns off any compiler optimizations and lets the code actually access the respective memory whenever dereferened.
Ad 2: there is no pointer to pointer; *((volatile uint32*)(0x04000000)) just dereferences the pointer (which has been explained in (1).
I guess this is about GameBoy Advance development.
You can write to a memory address without declaring any variable, a pointer is a type of value which represents a memory address, you can write and read from it without the need to store it anywhere.
It's not a pointer to a pointer, it's a hardcoded address which is cast to a (volatile uint32*), and the macro adds the * operator in front just to save you from writing it, which is just confusing.
I'm working on a framework for GBA development right in these days, maybe you can pick some informations or code from there, mind that code is C++14 though.

Failing to understand what the expression *(uint32_t*) does

I am failing to understand what the expression *(uint32_t*) does.
I have broken the statement down to an example that declares the parts so I can try and interpret what each one does.
uint32_t* ptr;
uint32_t num
*(uint32_t*)(ptr + num); // <-- what does this do?
I don't understand the last bit in the example, what happens when the expression *(uint32_t*)(ptr + num); executes during runtime?
uint32_t is a numeric type that guarantees 32 bits. The value is unsigned, meaning that the range of values goes from 0 to 232 - 1.
This
uint32_t* ptr;
declares a pointer of type uint32_t*, but the pointer is uninitialized, that
is, the pointer does not point to anywhere in particular. Trying to access memory through that pointer will cause undefined behaviour and your program might crash.
This
uint32_t num;
is just a variable of type uint32_t.
This
*(uint32_t*)(ptr + num);
ptr + num returns you a new pointer. It is called pointer arithmetic. It's like regular arithmetic, only that compiler takes the size of types into
consideration. Think of ptr + num as the memory address based on the original ptr pointer plus the number of bytes for num uint32_t objects.
The (uint32_t*) x is a cast. This tells the compiler that it should treat the expression x as if it were a uint32_t*. In this case, it's not even needed,
because ptr + num is already a uint32_t*.
The * at the beginning is the dereferencing operator which is used to access the memory through a pointer. The whole expression is equivalent to
ptr[num];
Now, because none of these variables is initialized, the result will be garbage.
However, if you initialize them like this:
uint32_t arr[] = { 1, 3, 5, 7, 9 };
uint32_t *ptr = arr;
uint32_t num = 2;
printf("%u\n", *(ptr + num));
this would print 5, because ptr[2] is 5.
uint32_t is defined in stdint.h, so one may need to include it
#include <stdint.h>
this header shall define uint32_t to be an unsigned integer type taking exactly 32 bits.
This doesn't really do anything. Let me give you a different example:
uint32_t data;
void *pointer = &data;
*(uint32_t *)pointer = 5;
First of all, void* means "generic" pointer. It can point to objects of any type.
Now, (uint32_t *) means "interpret pointer as a pointer to an object with type uint32_t.
The rest of the expression simply means "store 5 at the location stored by this pointer".
If you want to know what uint32_t is, that's an unsigned integer with exactly 32 bits. And pointer + num is the same as the adress of pointer[5].
This type of expression is usually used in type punning. If you're not familiar with type punning, the main idea is to bypass the type system so that you can treat something as a different type than it really is (ie treat an int a as double)
The main idea behind type punning is you take a pointer to a current variable and then pun it into a different type by casting it into a pointer of that type and then dereferencing it, hence the commonly used cast and dereference you are referring to ( *(uint32_t *) = cast to unsigned 32bit int pointer and then dereference).
As others have pointed out, your code "does nothing" because you are punning an int to an int, which has no effect. If you wanted to pun an int into a double however...
uint32_t num=5;
double& myvar=*(double*) &num;
Now you can manipulate nums memory as a double via myvar even though num is still an Int. This is a terrible idea and is just meant as a toy example of the use of punning.

pointer assignment to a variable

addr is a parameter to the function and read_value is a local variable of the function. both are of type int.
Then what does:
read_value = (* (int *) (addr))
mean?
(int *) (addr) casts the numeric value of addr to an int * pointer. Unless special care is taken, this operation is unsafe because an arbitrary value of addr can violate the alignment requirements for int. In general, if the value of addr is not a multiple of the size of an int, it can lead to a misaligned read which can eventually result in a SIGBUS signal.
The asterisk finally fetches the int value located at that address (called dereferencing) and saves it into read_value. It is at this point where the misaligned read can happen, if the address is not sufficiently aligned. The dereference might as well cause a segmentation fault if the address happens to be restricted or protected.
I would actually declare addr to be of type uintptr_t, rather than int, since that gives more safety between the cast to int *. uintptr_t should correspond to the size and the representation of a pointer, while the int type is semantically unrelated to a pointer.
You cast addr to a pointer to int, dereference it, and put it in read_value .
If addr is really int, I think that it's undefined behavior.
Take the following example:
int read_value = 0;
int address = 0x1234;
read_value = *(int *) address;
This is equivalent to:
read_value = *(int *) 0x1234;
this reads an int at address 0x1234 and stores it in read_value object. It is done by first converting the int value 0x1234 to a pointer to int and then dereferencing the pointer to access the int value pointed at.
Note that the conversion (int *) 0x1234 is implementation defined.
(C99, 6.3.2.3p5) "An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation."
And the dereference of the pointer is undefined behavior if it is an invalid pointer or if it doesn't have the correct alignment. Any use of an invalid pointer is undefined behavior. An invalid pointer is a pointer that is not null but that doesn't point to a proper object or function.

Resources