access an array from known address - c

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)

Related

How to Cast Integer Value to Pointer Address Without Triggering Warnings

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.

Why do I get warnings when I try to assign the address of a variable to a pointer that was declared to point to a variable of a different type?

Take a look at the following program. What I don't understand is why do I have to cast the address of the variable x to char* when it actually would be absolutely useless if you think about it for a second. All I really need is only the address of the variable and all the necessary type information is already in place provided by the declaration statement char* ptr.
#include <stdio.h>
int main(void) {
int x = 0x01020309;
char* ptr = &x; /* The GCC compiler is going to complain here. It will
say the following: "warning: initialization from
incompatible pointer type [enabled by default]". I
need to use the cast operator (char*) to make the
compiler happy. But why? */
/* char* ptr = (char*) &x; */ /* this will make the compiler happy */
printf("%d\n", *ptr); /* Will print 9 on a little-endian machine */
return 0;
}
The C Standard, 6.2.5 Types, paragraph 28 states:
A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.
Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and
alignment requirements. All pointers to structure types shall have
the same representation and alignment requirements as each other.
All pointers to union types shall have the same
representation and alignment requirements as each other.
Pointers to other types need not have the same representation or alignment requirements.
Since different types of pointers can have differing implementations or constraints, you can't assume it's safe to convert from one type to another.
For example:
char a;
int *p = &a
If the implementation has an alignment restriction on int, but not on char, that would result in a program that could fail to run.
This is because pointers of different types point to blocks of memory of different sizes even if they point to the same location.
&x is of type int* which tells the compiler the number of bytes (depending on sizeof(int)) to read when getting data.
Printing *(&x) will return the original value you entered for x
Now if you just do char* ptr = &x; the compiler assigns the address in &x to your new pointer (it can as they are both pointers) but it warns you that you are changing the size of the block of memory being addressed as a char is only 1 byte. If you cast it you are telling the compiler that this is what you intend.
Printing *(ptr) will return only the first byte of the value of x.
You are correct that it makes no practical difference. The warning is there to inform you that there might be something fishy with that assignment.
C has fairly strong type-checking, so most compilers will issue a warning when the types are not compatible.
You can get rid of the warning by adding an explicit cast (char*), which is you saying:
I know what I'm doing, I want to assign this value to my char* pointer even if the types don't match.
Its just simple as you assign integer type to character. similarly you are trying to assign integer type pointer to character type pointer.
Now why is so because this is how c works, if you increment a character pointer it will give you one byte next address and incrementing integer pointer will give you 2 byte next address.
According to your code, x is of type int. So the pointer that points to x should be of type int *. Compiler gives such error because you use a pointer which is not int *.
So make your pointer either int *, or void * then you don't need cast.

Difference between address of a variable and integer

Whats the difference between integer and the address returned by & ?
Therefore, why should I type-cast integer to an integer pointer when assigning it to an integer pointer?
Integer and pointer to integer are different types.
Integer variable holds integer value.
Pointer variable holds address value.
Given your example:
int value = 5;
int address = &value;
value is variable of type int.
&value returns address of type int*
address = &value tries to assign int* to int.
While integers can be converted to pointers and back, it doesn't mean that addresses are necessarily integer values.
Just like you can assign double to int, you can assign int * to int. But it's not necessarily what you want, and that's why compiler warns about it.
In fact, unless you are working very close to hardware (writing driver for example), it's very unlikely you need to do conversions between integers and pointers.
Correct way to do this, without needing any casts:
int * pointer = &value;
Whats the difference between integer and the address returned by & ?
I think this question has already been answered in the comments. The difference is the type of those variables. Basically int = Integer type and *int = Pointer type.
Furthermore: Conversion from pointer to int can result in undefined behavior.
Therefore, why should I type-cast integer to an integer pointer when
assigning it to an integer pointer?
Because the standard says:
C99 Section 6.5.4 and 6.5.16.1:
Conversions that involve pointers, other than where permitted by the
constraints of 6.5.16.1, shall be specified by means of an explicit
cast.
And C++ Section 5.4:
Any type conversion not mentioned below and not explicitly defined by
the user (12.3) is ill-formed.

Why should I use double pointer variable to receive another pointer's address(&ptr1)

int num = 45,*ptr1,*ptr2;
ptr1=&num;
ptr2=&ptr1;
printf("%d\n",*ptr1);
I've been thinking about this question for a while, but couldn't find a way to understand it,why &ptr1 can not be assigned to ptr2 in line 3, &ptr1 is a pointer's address,this address is no different from other address like an address of an integer, say
int a=1;
ptr2=&a;
Which means that I can assign an integer's address to a pointer,but not a pointer's address to a pointer,what differences between these two "address" could possibly make them different? Address of common variables can be assigned to single pointer,but address of pointers can not be assigned to single pointer?
I know the right way to do it is use double pointer to declare ptr2,but why single pointer can't?
Simply put, pointers are not addresses, they are varibles representing an address with a type. So the types have be compatible for pointers to assign (with the exception of void * generic pointer).
ptr2 = &ptr1;
ptr1 has a type of int *, so &ptr1 has a type of int **, it's not the same with ptr2, which has a type of int *.
Reference: C99 6.5.16.1 Simple assignment
both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right.
Yes you can assign a pointer's address to a pointer, but it must be a pointer to a pointer variable.
int **ptr3;
ptr3 = &ptr1;
The reason you can't assign it the way you were trying is that a pointer to an int is not the same as an int. Pointers must be pointing to the same type to be compatible. If you really know what you're doing you can explicitly cast it, but that's a path to danger.
Your code is wrong. This expression:
ptr2 = &ptr1;
Attempts to make an int * out of an int ** without a cast. The C standard forbids such conversions without an explicit cast.
The reason it's not allowed is that pointer types aren't guaranteed by the standard to all be the same size - so the pointer to your pointer might not fit in the variable you declared to be a pointer to an int.
Since pointers to any type can be converted to and from void * implicitly, you could write (correct, but probably confusing) analogous code to that in your question:
int num = 45;
void *ptr1, *ptr2;
ptr1 = &num;
ptr2 = &ptr1;
But doing so will require you to carry around all of the type information in some other way:
printf("%d\n",*(int *)ptr1);
printf("%d\n",*(int **)ptr2);
The short answer is that type matters; a pointer to int is a different, incompatible type from pointer to pointer to int. As others have mentioned, different pointer types may have different sizes and representations.
A pointer value is not just an address; it has additional type semantics. For example, the expression ptr++ will advance the pointer to the address of the next object of the base type. If the base type is char, then the pointer is advanced 1 byte. If the base type is int, the pointer is advanced sizeof (int) bytes.
Simply put because it will confuse the compiler. The compiler can work only according to the language standard. It doesn't have a brain of its own.
The language standard tells the compiler that if there is a int *
go to the address stored in that variable and use it.
In case there is a int ** then it tells it
go to the address in that variable. You aren't done yet as that is also an address. Go there and use what is present there.
This goes on and on for int *** and so on.
Hope this helps you to get over this basic confusion.
If you could assign any address to any pointer regardless of type, on the grounds that one address is just like any other address, consider the trouble you could get yourself into if the following became legal:
int n = 40;
int * p = &n;
int ** pp = &n; /* Typeless address assignment as you would like */
printf("%d\n", **pp); /* Bad Things happen here */
or the other way round:
int n = 40;
int * p = &n;
int * p2 = &p; /* More typeless address assignment */
printf("%d\n", *p2); /* Definitely not what you want */
Even if one address was the same as any other, sensibly dereferencing a pointer would become somewhat troublesome if things worked the way you suggest.
The reason you can't do what you suggest is that the type information you'd lose under your proposal is needed for dereferencing to work. If all you wanted pointers to do was to store and retrieve addresses, you'd have a point, but they're not just used for this. If they were, we could just have void pointers and be done with it.
I completely agree to your statement that when pointer variable always would store a value that is integer, as the address to any variable/array would be an integer.
But still the data-type that is used to declare the pointer is the one of whose address it would be storing.
There are 3 points:
1. The bits that are used while storing integer values differ from machine to machine.
i.e. 32-bit, 64-bit and further more complications may add-up.
2. Memory occupied i.e. bytes of data stored in it. Reason is : somewhere even the pointer variable is stored in memory. Right?
3. There are certain operations associated with pointers like ++ or --.
Remember, pointer type is dependent on the type of variable it points to.
This is the reason/need for the pointer to pointer.

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