We have some float x and we convert it into i, but could anyone please explain what does do in depth first &, then cast and finally *?
int i = *(int*)&x;
&x
Gets a pointer to x
(int*)&x
Casts that pointer to an int*, i.e. a pointer to an int
*(int*)&x
Dereferences the resulting pointer, reading the memory of variable x as if it were an int.
Without knowing the type x is, it's hard to tell what the code's purpose. Most likely, if x is a float, it's being used to get the binary representation of the float (which is impossible to do by just casting to an int, because it does a float to int conversion)
&x: Get a pointer to x
(int*): Cast that pointer to a pointer to an int - this does not actually cast x
*: Retrieve the value the pointer points to
Since a pointer cast doesn't actually perform type conversion, this line of code has the effect of reading the internal bits used to store the float x, and storing those bits int the integer i. Basically, this is a reinterpret_cast. (reinterpret_cast is a C++ feature, but it does exactly the same thing as this C syntax.)
"&" means getting the reference of a variable. So &x gets the reference to a float and has type float*.
(int*) is a cast. Therefore you are casting from float* to int*.
The last "*" is for dereferencing the int*, that is, getting the value of the int*, which is an int.
Lets break it down
&x; //this gets you the address of x
(int *)&x; //this cast the address to be pointing at an integer value
//(before it was pointing at a float value)
*(int *)&x; // now the last * dereferences that value
assuming in your system, long is 8bytes and int is 4bytes. so you get only 4 bytes of the 8 bytes of x. As int is usually 4 bytes and long 8 bytes. Now which of the 4 bytes you get (the first 4 or the last 4) depends on the endianness of your system..
For more info on endianness, read this http://en.wikipedia.org/wiki/Endianness
Related
Not sure if I'm phrasing the question properly nor how to best explain what I'm trying to have answered so bear with me.
When defining a microcontroller register, you would write something like this:
#define io_register (*(volatile unsigned char *)0x25)
I also found this line of code here: Pass a hex address to a Pointer Variable
int *pointer = (int *) 0x00010010;
I understand that a pointer that points at an int is being declared left of the = sign, but why is there a typecast *(int ) right of it?
Same with the #define, I understand that the value at 0x25 is being dereferenced but why am I not able to write it like this:
#define io_register *(0x25)
or
int *pointer = 0x25;
What am I missing here? Please feel free to rephrase or correct any mistakes I've made, still trying to wrap my head around pointers and registers.
An important prerequisite of any assignment operation is data type compatibility. In other words, the data type of the equation's (int *pointer = 0x25;) LHS (int *pointer) must be compatible with whatever data type results from the evaluation of the equation's RHS (0x25).
For example, if both LHS and RHS are int types, then there will be no problem assigning the integer value of RHS to LHS.
But, in this expression:
int *pointer = 0x25;
you have int * data type in LHS and int data type in RHS. So, there's an incompatibility between LHS & RHS. That's why you need to cast RHS to (int *).
The cast suppresses the warning. That is its role in those statements. Otherwise it will be casted implicit way, and warning omitted. No difference in the code or program execution.
#define io_register *(0x25)
*(0x25) will not be a pointer in any circumstanes and io_register when used means : multiply by 0x25.
int x = 10 io_register;
which means: int x = 10 *(0x25);
With
int *pointer = (int *) 0x00010010;
You are telling the pointer to point to an absolute address in memory, the value at that address can be dereferenced with *pointer.
With
int *pointer = 0x25;
The compiler does not like that because 0x25 is an integer but pointer is not an integer, it is an integer pointer.
The cast is needed because 0x00010010 is not a pointer but an integer (it is the first type among int, unsigned int or long int that can represent the value 65552) .
Only integer constant expressions having value of 0 can be converted to a pointer implicitly (i.e. without a cast); the resulting pointer would be a null pointer.
You can naturally write
#define io_register *(0x25)
but you cannot use that io_register to access memory at address 0x25, because that 0x25 is not a pointer - it is an integer.
In C one does not really access addresses; instead one dereferences pointers to get lvalues that designate an object, and then get the value of that object, or a set a new value to it.
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*) #
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.
#include<stdio.h>
int main()
{
float a=10;
float* p=&a;
printf("%u\n",p);
p=p+3;
printf("%u",p);
}
After execution of this program I got 2 memory addresses as an output, thelatter with a value greater by 12 than the former.
#include<stdio.h>
int main()
{
float a=10;
float* p=&a;
printf("%u\n",p);
p=p+3.5;
printf("%u",p);
}
I tried changing 3 to 3.5 but I got an output with equal values of both the addresses. I expected that the value would increment at least by 12 in either cases.
What could be the reason ?
That's how pointer arithmetic works. It's designed to work on arrays.
float array[4];
float *q;
q = array; /* Now q points to the first element of the array: q == &array[0] */
printf("%p\n", q);
q += 3; /* Now q points to the fourth element of the array: q == &array[3] */
printf("%p\n", q);
When you add an integer to a pointer, it points that many elements further into the array. If the size of the array elements is N bytes, then adding x to a pointer adds x*N to the address.
On your machine, it appears that sizeof(float) is 4: you see that x*N=12, with x=3, so N=4.
Note that there are several errors in your code. In your program, p=p+3 has undefined behavior because p points to a single float (which has the same memory layout as an array of 1 float). It is an error to make a pointer point outside the boundaries of an object. On a typical PC compiler you just silently get an invalid pointer; a rare few implementations would detect the invalid pointer as soon as it's computed and abort the program with an error.
Printing the pointer value with %u is also an error. In practice it may work, print garbage, or crash, depending on your compiler and on whether pointers have the same size as unsigned int. Any halfway decent compiler would warn you that printf("%u", p) is incorrect; if yours doesn't, make sure to enable its useful warnings (e.g. gcc -O -Wall if you're using GCC).
There is only three types of pointer arithmetic is allowed in C:
Adding an integer to a pointer.
Subtracting an integer from a pointer.
Subtracting one pointer from another (they should point to same array).
Standard says that:
C11:6.5.6 Additive operators:
2 For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)
3 For subtraction, one of the following shall hold:
— both operands have arithmetic type;
— both operands are pointers to qualified or unqualified versions of compatible complete object types; or
— the left operand is a pointer to a complete object type and the right operand has integer type.
Any other arithmetic operation is invalid and will invoke undefined behavior. Note that the correct specifier for printing address is %p.
the program contains several errors and poor programing practices
#include<stdio.h>
int main()
{
float a=10; // init floats with float values, so use '10.0f'
float* p=&a;
printf("%u\n",p); // print addresses with '%p' not '%u'
p=p+3; // now 'p' is pointed to some unknown area
printf("%u",p); // print addresses with '%p' not '%u'
}
good thing the code did not 'de-reference' 'p' after 'p'
was modified, because that would have been undefined behaviour
possibly leading to a seg fault event
int num = 45,*ptr1,*ptr2;
ptr1=#
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 = #
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.
int x=10;
int *y=&x;
int *z= &y;
printf("%d\n",*(*z));
I want to understand why we need int **z? What is wrong here?
Here's a handy table showing the types of various expressions based on your declarations:
Expression Type Value
---------- ---- -----
x int 10
&x int * address of x
y int * address of x
&y int ** address of y
Since the type of the expression &y is int **, you need to declare z as int ** to hold that value (and thus the expression &z would have type int ***).
So, why does it matter? A pointer is a pointer is a pointer, right?
Well, not necessarily. Pointers to different types may have different sizes and representations. From the online 2011 standard:
6.2.5 Types
...
28 A pointer to void shall have the same representation and alignment requirements as a
pointer to a character type.48) 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.
48) The same representation and alignment requirements are meant to imply interchangeability as
arguments to functions, return values from functions, and members of unions.
In the desktop and server world, most architectures are such that all pointers types have the same size and representation, but there are plenty of oddball architectures where that isn't true. You can have a word-addressed architecture where multiple char values are packed into a single word; a char * would need to have a couple of extra bits to index into that word to get to a specific char value. You can have a Harvard architecture where you have fewer address lines for data than you do for code (or vice versa), so pointers to object types and pointers to function types will have different sizes.
There's another issue at play here: pointer arithmetic. Since y points to an object of type int, the expression y++ will advance y to point to the next object of type int. Since z points to an object of type int *, the expression z++ will advance z to point to the next object of type int *. If int and int * have different sizes, then y and z will be advanced by different amounts.
In short, type matters, even for pointers.
Let's take it a step at a time, shall we?
int x = 10;
This code creates an int variable at some memory location and sets its value to 10. This variable can be accessed by the convenient name x.
int *y=&x;
This code creates a pointer to an int variable at some memory location and sets its value tot he address of the x variable. This variable can be accessed by the convenient name y. If you printed the value or y you would get the address of x. If you dereferenced y (by doing *y) and printed the result then you would get 10
int *z= &y; // error
This won't compile: z is a of type pointer to int. Since y is already a pointer to int, when you take its address (by doing &y) what you get back is a pointer to pointer to int. That's why you need the double star.
int **z = &y;
Now this will compile. This code creates a pointer to a pointer to int variable and sets it value to the address of the variable y. If you printed the value z now, you would get get the address to y. If you dereferenced z (by doing *z) and printed the result you would get the address of x.
x is a variable of type int, meaning it holds an integer value. The type of 10 is int.
y is a variable of type int*, meaning it holds a value representing a memory address at which a value of type int is stored. The unary operator & produces the memory address of its argument, and generally the type information is included along with that, so as x is an int the type of the address of whatever is held by x will be int*.
z is a variable of type int**, meaning it holds a value representing the address of a variable of type int*. &y produces the memory address of y, and thus the result is of type int**.
The reason why the type information is included is not just a matter of strict/static typing; the way pointer arithmetic is performed (e.g. p++, equivalent to p += 1) will differ depending on the size of the type being pointed to. So for a pointer to a 4-byte value, incrementing the pointer by 1 will result in a pointer to the location four bytes after the original, while for a pointer to a 1-byte value, incrementing the pointer by 1 will result in a pointer to the location one byte after the original. Essentially, adding an integer to a pointer results in pointer_value + integer*sizeof(underlying_type).
You can, of course, use inline casts on the pointer type to alter the factor on the integer, but that's a topic for another time.
You need a double star because of this.
x = 10 (the memory at the address of x holds hte value 10).
y = the address of x. If you dereferenced y (*y), it would show you 10. If you printed the value at the address of y, it would show you the address of x. If you print the address of y, it will show you something different from these 3 things.
z = to address of y. Remember, when you dereference z now (*z), it is going to give you the value held at y, which is the address of x. When you double dereference this, it gives you the value at address of x, which is what you want (hence, why you need the double dereference).
In c/c++, it's helpful to read variable declarations from right to left in order to get a better understanding of what their types are. In your code segment, this would produce the following description:
x is an int
y is a pointer to an int
z is a pointer to an int
In the first line, you're assigning 10 to x. Since 10 is an int, this succeeds without problems.
In the second line, you're assigning the address of x to y. Since pointers hold addresses, x is an int and y is a pointer to an int, this line succeeds as well.
The third line is where you hit your snag. You're assigning the address of y to z. z is expecting an address to an int by it's getting the address of a pointer to an int.
As DardDust mentioned, you need to change your definition of z so that it's a pointer to a pointer to an integer.
int **z = &y;
Once you've got that, it will be easier to understand the last line and your first question.
the printf function is expecting an int but you're using z. In order to get the int value, you need to do a double dereference. The first dereference will return a pointer to an int, the second the int itself.
x is a variable of type int which is stored somewhere in memory.
&x returns the address of the memory location where x is stored. That's a pointer. Thus the type returned by &x is int *. Now, this pointer is again stored somewhere in memory, using variable y.
And then you want to get the address of z via &y. The variable y already stores a pointer, so now you have a pointer to a pointer to an int, that is a int **.
In the printf statement, you then need to crawl that chain back:
The inner *z reads the memory pointed to by z. Since z has the memory location of y, *z return the memory location of y.
And then you read the memory pointed to by y (indirectly). And y points to x, so you end up reading x.
A bit mind twisting, but vital to understand when working with C.
For every time you need a pointer to you need to add a * to your type:
int x=10;
declares an int and assigns to it the value 10
-> no a pointer to so no *
int *y=&x;
declares a pointer to an int and saves and assigns to it the address of where x is stored
-> 1 a pointer to so 1 *
and finally
int **z= &y;
declares a pointer to a pointer to an int and assigns of it the address where y is stored
-> 2 a pointer to so 2 *