Is a c++ dereference an lvalue or an rvalue? - c++

I am confident I understand the meaning of rvalue and lvalue. What's not clear to me is whether a dereference is an rvalue.
Consider this:
#define GPIO_BASE 0x20200000
#define GPFSEL1 (*(volatile unsigned int *)(AUX_MU_BASE + 0x4))
GPFSEL1 is a dereference to an unsigned int pointer. That unsigned int pointer is a physical address of a hardware register.
I have read that this is a common technique in bare metal programming to access hardware registers directly. So far I am able to use it with no problem.
Now I want a reference to GPFSEL1 as a member of a struct. Is this possible?
struct MotorControl
{
u8 pwm_pin;
u8 ctrla_pin;
u8 ctrlb_pin;
volatile unsigned int* MYGPFSEL; // this is not the same thing so does not work
}
Given this function below, what's the correct way to reference GPFSEL1 which is defined elsewhere and how to dereference it to set the its value?
MotorContorl group
group.MYGPFSEL = ?
void set(unsigned char pin_number, bool high)
{
if (high)
{
// how to correct this statement
group.MYGPFSEL |= 1<< pin_number;
}
}

"Dereference" is a verb - you dereference a pointer to get access to the value it points to.
The type conversion is straightforward - if you have a pointer to an integer, and you dereference it, you're now working with an integer. It's an lvalue, as it (by construction) takes up a location in memory, and one that you can (usually) modify.
int x = 10;
int* xptr = &x;
*xptr = 5; // *xptr is an lvalue
std::cout << "X: " << x << std::endl; // Prints 5
However, the pointer needs to point to a place in memory. If you just start with
int* xptr;
*xptr = 5;
You're going to get an error, since you're trying to dereference a pointer that doesn't point to a valid memory address. (And if it does, that's purely by coincidence, and you'll incorrectly change the value.)
If you want a reference to GPFSEL1 as a member of your MotorControl struct, you will not be able to initialize the struct without passing it the object to which it will reference. What you probably want instead is a pointer inside the struct, which is much easier to work with:
MotorControl myMotorControl;
myMotorControl.MYGPFSEL = GPFSELF1;

Your current approach will work fine, you just need to initialize the member variable appropriately, e.g.
struct MotorControl control;
control.MYGPFSEL = (volatile unsigned int *)(AUX_MU_BASE + 0x4);
alternatively you can initialize it as
control = &GPFSEL1;
given that you have defined GPFSEL1 as in your original question:
#define GPFSEL1 (*(volatile unsigned int *)(AUX_MU_BASE + 0x4))`
Now you can read the register:
foo = *control.MyGPFSEL;
or set the register:
*control.MyGPFSEL = 123;

This is an easy question to answer, a dereference can be the left-hand side of an assignment so it's an l-value.
Easy case to illustrate:
char sz[] {"hello"};
*sz = 'j';
If something can be the left side of an assignment it is by definition an l-value.

Related

Why do variable pointers contain the address of the same data type?

General syntax of pointer declaration: data-type *pointer_name;
A pointer is a variable whose value is the address of another variable, i.e., direct address of the memory location. Like any variable or constant, you must declare a pointer before you can use it to store any variable address. The data type of pointer must be same as the variable, which the pointer is pointing.
Why is it important that a pointer variable should contain the address of a variable of the same data type?
As a pointer has nothing to do with the value of another variable, why can't an integer pointer have the address of float data type variable?
Correct form:
int a = 10 ;
int *ptr = &a ;
ERROR, type mismatch
float a;
int *ptr; ptr = &a;
Because when you increase a pointer like
ptr++;
it will point to an address that is one multiplied with the size of the data type. If you do
ptr+=2;
and the data type is occupying 4 bytes which would be the case if the pointer was declared as
float *ptr;
the pointer will increase with 8 byte positions.
Before answering that, let me ask you, if it were valid, what would you do with such a pointer?
Suppose you have (inside a function)
float a;
int *ptr; ptr = &a;
*p = 1;
++*p;
return *p;
In such a case, there is no reason at all not to just use an int variable if it's an int you want.
Suppose you have (inside a function)
float a;
int *ptr; ptr = &a;
a = 3.14;
++*p;
return a;
In this sort of object aliasing, there can be a use, but allowing constructions like this is a pain for compilers. Compilers are free to assume, and some do assume, that the modification of *p has no effect on the value of a, so still return 3.14 unmodified;
If the latter case is something you're looking for, you can use union, which both makes your code clearer to other readers, and makes your code clearer to the compiler:
union {
float f;
int i;
} u;
u.f = 3.14;
++u.i;
return u.f;
So, to answer: it's to prevent you from shooting yourself in the foot. It's not allowed because there is no way such a pointer is useful. The one case where it could be useful is actually a case where it doesn't work, and there is another language construct that does handle it, and handles it correctly.
There is also the simple matter of dereferencing the pointer.
something = *pointer;
How much data should be read when the pointer is dereferenced? The compiler must know the data type in order to perform operations on the data like fetch, add, etc.
It's a safety feature. A pointer of one type pointing to a variable of another is a recipe for disaster; it has almost no legitimate purpose and almost anything you do with it is dangerous, especially if the types are of different sizes.
You can override this feature by means of casting. If you do so, you can no longer claim that you didn't know you were doing something dangerous.
It is possible for pointers to point to any data type: that's exactly what void pointers are for. You can use a void * to point to any data type1, and then you can get the original pointer back.
float f = 1.0f;
int i = 12;
void *p = &f;
p = &i;
Of course, you can't dereference a void pointer without first casting it back to the correct pointer type. It is up to you to ensure that the pointer type is correct.
// In C, this is valid: implicit conversions to void * and back.
float f = 1.0f;
void *p = &f;
float *fp = p;
printf("*fp = %f\n", *fp);
// In C++, you have to use a cast:
float *fp = static_cast<float *>(p);
Void pointers have limitations: you cannot dereference them, and you cannot do any pointer arithmetic.
1: Function pointers should not be cast to void *.
Lets understand it with an example.
int main()
{
char i = 8;
int *ptr = &i;
printf("Value of i = %d", *ptr);
return 0;
}
Ans: It will print some garbage because it dereferenced 4 byte in memory.
so if you do char *ptr = &i;, it will dereference 1 byte and so on..
It will give correct answer.

References and Pointers both store addresses?

Does int* var and &var both store addresses, the only difference is that you have to deference int* to get the value back but don't references already do that? Having trouble understanding these thoroughly.
And why is that when you have a function that accepts int* into the parameters you can pass values in by &
They are different ways of expressing what probably eventually boils down to the same thing. They are both constructs that have been invented by the language's designers, meaning your compiler's authors must implement them in whatever manner they see fit for the underlying machine.
However, just because they may represent the same thing on the machine doesn't mean that they are equivalent. Pointers allow the concept of pointing-to-nothing-ness (NULL pointers) and also allow one to perform mathematic operations to obtain a portion of memory indexed off of a starting position... like so:
int *x = new int [10];
*(x+2) = 5; //set the 3rd element of the array pointed to by 'x' to 5
is perfectly sensible.
References have no notions of such things, i.e. one can do
int *x = new int[10];
*(x+2) = 5;
int &y = *(x+2);
but not
int *x = new int[10];
*(x+2) = 5;
int &y = *(x+2);
y = y + 5;//this just changes the value of x[2]
which means it's more difficult to write off the end of a struct because of bad pointer math, so they are safer provided they've been initialized to something that makes sense (i.e. not returned from a function where they are declared on the stack or to an array element that doesn't exist)
int &dontdoit() {
//don't do this!
int x = 7;
int &y = x;
return y;
}
I think this is perfectly legal and safe in that you won't be corrupting memory, but it's not recommended as you're mixing idioms and you have no way to free the resulting allocated memory:
int &dontdothiseither() {
int *x = new int;
int &y = *x;
return y;
}
Also, you can set a pointer as many times as you like but not a reference.
int x[2];
int *y = x;//works
y = y+1; //works, now points to x[1];
int &z = x[0]; //works
z = x[1];//nope! This just sets x[0] to be the value in x[1]
int* is a variable whose value is the address of some int. &var is not a reference. The unary & operator simply returns the address of var. That's why if you have a function that takes a parameter of type int*, you use &var at the calling site.
It's a bit confusing since C++ uses & to mean both "address of" and "reference", but the context is what makes them different.
int a = 5;
int& ref = a; // Now ref and a both mean the same thing.
vs
int b = 6;
int* ptr = &b; // Now ptr POINTS to b, but they are not the same thing.
no no no!
references become nickname of that variable, where as pointers store variable's address.
suppose we have a variable of type int :
int x;
int &y=x; // now y is an other name of x
int *p=&x; // here p is a pointer, which points to x
Yes, pointers and references both store addresses, and are compiled to exactly the same code. The only major difference though is that references cannot be null, whereas pointers can - hence the well-known "null-pointer". Obviously they are accessed in different ways by the programmer: using -> and . respectively but that is really of no significance.
You can view a reference as a new "name" for a variable, while a pointer is a variable storing an address.
In practice, a reference might be implemented with pointers (so, it might store an address), but you do not need to worry about that.
For example:
int i;
int *pointer = &i; //Holds address of i
int& reference = i; //reference is a new name of i
int *pointer2 = &reference; //pointer2 holds the address of i
Yes, internally passing a pointer to T and passing a reference to T are the same in any known sensible implementation, references being semantic sugar for pointers which are always dereferenced and cannot be NULL.
Implementations are not obligated to make sense though.
After optimization, that is even sure for references used inside a function.
Still, they lead to different method / object signatures.
Also, they have different semantic load for the reader.
The & character is used for many different purposes in C++. Two of them look like they might be similar, but they're not.
The first is to create a reference:
int a = 1;
int &b = a;
Now a and b both refer to the same variable, and a change made to one will be reflected in the other.
The other usage is to create a pointer:
int *p = &a;
This has nothing to do with references at all. The & is being used as an address-of operator, taking the variable and creating a pointer that points to it.

Assigning int value to an address

I thought the following codes were correct but it is not working.
int x, *ra;
&ra = x;
and
int x, ra;
&ra = x;
Please help me if both of these code snippets are correct. If not, what errors do you see in them?
Your both expressions are incorrect, It should be:
int x, *ra;
ra = &x; // pointer variable assigning address of x
& is ampersand is an address of operator (in unary syntax), using & you can assign address of variable x into pointer variable ra.
Moreover, as your question title suggests: Assigning int value to an address.
ra is a pointer contains address of variable x so you can assign a new value to x via ra
*ra = 20;
Here * before pointer variable (in unary syntax) is deference operator gives value at the address.
Because you have also tagged question to c++ so I think you are confuse with reference variable declaration, that is:
int x = 10;
int &ra = x; // reference at time of declaration
Accordingly in case of the reference variable, if you want to assign a new value to x it is very simply in syntax as we do with value variable:
ra = 20;
(notice even ra is reference variable we assign to x without & or * still change reflects, this is the benefit of reference variable: simple to use capable as pointers!)
Remember reference binding given at the time of declaration and it can't change where pointer variable can point to the new variable later in the program.
In C we only have pointer and value variables, whereas in C++ we have a pointer, reference and value variables. In my linked answer I tried to explain differences between pointer and reference variable.
Both are incorrect.
When you declare a pointer, you assign it the address of a variable. You are attempting the other way round. The correct way would be:
int x,*ra;
ra = &x;
Both of those causes, in the way you have them in your question, undefined behavior.
For the first, you don't initialize the pointer, meaning it points to a random location (or NULL if the variable is global).
For the second, you try to change the address the variable is located at, which (if it even would compile) is not allowed.
Here's some annotated code:
int main () {
// declare an int variable
int x = 0;
// declare a pointer to an int variable
int *p;
// get the memory address of `x`
// using the address-of operator
&x;
// let `p` point to `x` by assigning the address of `x` to `p`
p = &x;
// assign `x` a value directly
x = 42;
// assign `x` a value indirectly via `p`
// using the dereference operator
*p = 0;
// get the value of `x` directly
x;
// get the value of `x` indirectly via `p`
// using the dereference operator
*p;
}
Note that dereferencing a pointer that doesn't point to a valid object of the specified type is not allowed.
So you normally shouldn't do things like the following (unless you really know what you are doing):
*(int*)(12345) = 42; // assign an integer value to an arbitrary memory address
Here is my 2 cent.
If you are going onto understanding pointer in C. First make the distinction between * the operator and * the type qualifier/specifier.
See that in C * is a syntaxique element that can plays both role but never at the same time. A type qualifier:
int a;
int * c = &a;
int * my_function_returning_pointer();
And for getting the proper int. As an operator. ( *c is an alias of a)
*c = 9;
I admit that is quite confusing and can trap a lot of beginner. Make sure that you recognize when * is used as an operator or when it is used as a type qualifier.
The same things apply to & although it is less often used as type qualifier.
int & f = returning_a_reference();
int my_function( int & refParam);
It is more often use for getting the address of an object. Thus it is used as an operator.
c = &f;
case 1:
int x,*ra;
&ra = x;
it is wrong in c, because in c we can point to a memory location by using a pointer ( i.e *ra in your case ). this can be done as fallows
int x, *ra; x ---------
ra=&x; ra --->1000 | value |
----------
NOTE : with out initializing a variable we can't use pointer to hold the address of that variable, so you better to first initialize variable, then set pointer to that memory location.
int x, *ra;
x=7;
ra=&x;
Fallowing may be helpful to you:
problems(mistake we do ) in handling pointers :
1.)
int a ,*p;
p=a; // assigning value instead of address. that leads to segmentation fault at run time.
2)
int a, *p;
&p=a; // look at here wrong assignment
3)
char *p="srinivas"
strcat(p, "helo" ) ; // we cant add a substring to the constant string.
4) int a=5, *p;
p=5; // the pointer here will points to location 5 in the memory, that may damage whole system, be care full in these type of assignments.

C++ type casting with pointers

I come from a background of C# and Java and I can't seem to understand what casting with pointers means in C++.
For example:
int x = 1;
char c = *((char*)&x);
What does it do? What it is useful for?
In both your examples you're making mistakes making the code not compile. So I'll assume you're trying to do the following:
int x = 1;
char c = *((char*)&x);
Depending on your architecture, c will now have either the value of the least or the most significant byte of x. In this example this would be either 0 or 1 (this can actually be used to detect the byte ordering).
Your second example won't work, cause you're trying to ignore the const resulting in an illegal operation/bad cast (this is also called "const correctness").
Edit: Regarding your comment about "what does it mean?":
In expressions:
&somevariable will return the address of somevariable.
*somevariable will assume the contents of somevariable are the address of the actual value, which is then returned.
In declarations:
datatype is a normal variable/object. This is passed "by value".
datatype& is a reference. This works exactly like normal variables in Java/C# and is passed by reference.
datatype* is a pointer. This just contains the address where the actual value is located (see above) and is essentially passed by reference as well.
Actual casts work pretty much similar to Java/C#, but pointers are just that: They point to the location of the actual value. While this might confuse you, pointers in C/C++ work pretty much like the standard variables/references used in Java/C#.
Look at this:
MyClass x; // object of MyClass
MyClass *x; // pointer to an object of MyClass - the actual value is undefined and trying to access it will most likely result in an access violation (due to reading somewhere random).
MyClass *x = 0; // same as above, but now the default value is defined and you're able to detect whether it's been set (accessing it would essentially be a "null reference exception"; but it's actually a null pointer).
MyClass &x = MyClass(); // creating a new reference pointing to an existing object. This would be Java's "MyClass x = new MyClass();"
Casting in C++ works just like casting in Java, no pointers involved.
int x = 1;
char c = (char) x; // Lose precision
However, what you are doing here:
int x = 1;
char *c = (char *)x;
is telling the compiler that the value of x is the address of a character. It is equivalent to
char *c;
c = 1; // Set the address of c to 0x0000000000000001
There are very few times you need to do this.
There are two fundamentally different concepts in C++ which are both sometimes referred to as "casting": One is conversion, and one is reinterpretation.
Conversion creates a new object with the "same value" as an existing object, but of a different type. Here are some examples:
Example 1: type promotion
// 1a: promote int to double to get the correct type of division
int numerator = rand(), denominator = rand();
double d = double(numerator) / double(denominator);
// 1b: convert int to double to achieve a particular argument deduction
int n;
template <typename T> void do_numeric_stuff(T x) { /* ... */ }
do_numeric_stuff(double(n));
Example 2: Derived-to-base conversion
struct B { }; struct D : B { };
D x;
D * p = &x; // pointer to x
B * q = p; // implicit conversion; may change the value!
On the other hand, reinterpretation allows us to treat one variable as though it was another one. About the only correct and useful application for this is serialization, in one form or another.
Example 3: Serialization
std::ofstream file("output.bin"); // output file
char large_buffer[HUGE]; // in-memory buffer
unsigned int n = get_data();
char const * p = reinterpret_cast<char const *>(&n);
file.write(p, p + sizeof n); // write the bytes of `n`
std::copy(p, p + sizeof n, large_buffer); // ditto
std::copy(large_buffer + 17, large_buffer + 17 + sizeof n,
reinterpret_cast<char *>(&n)); // repopulate `n` from buffer
The standard says that it is undefined behaviour to access an object through a pointer that is not of the correct type (also called "type punning"). While it is OK to store an object pointer in, say, a void* and then convert it back and use it, it is not OK to treat a float as though it was an integer, etc. The only acceptable way of accessing one object as though it was another is the one I demonstrated, namely treating an object of type T as though it was an array char[sizeof(T)] — that is, you are allowed to access the underlying binary representation of every object.
You should avoid c-type casts like (char*) by all means. If you really have to do a type cast have a look at dynamic_cast, static_cast and reinterpret_cast.
But as already stated, you rarely need casting at all.
Have a look here for fruther information:
http://www.cplusplus.com/doc/tutorial/typecasting/
http://www.parashift.com/c++-faq/static-typing-and-cpp.html
http://www.parashift.com/c++-faq-lite/print-char-or-ptr-as-number.html
I used many time ago that idiom to access HW at specified address, on custom IO board. So for instance to write at PIC (programmable interrupt controller) to reset some flag (fictious code):
#define PIC_LOC 0x1000
#define PIC_ENABLE_PORT *((char*)(PIC_LOC+0x10))
#define BIT_ENABLE (1 << 3)
...
PIC_ENABLE_PORT |= BIT_ENABLE;
...

C++ Returning Pointers/References

I have a fairly good understanding of the dereferencing operator, the address of operator, and pointers in general.
I however get confused when I see stuff such as this:
int* returnA() {
int *j = &a;
return j;
}
int* returnB() {
return &b;
}
int& returnC() {
return c;
}
int& returnC2() {
int *d = &c;
return *d;
}
In returnA() I'm asking to return a pointer; just to clarify this works because j is a pointer?
In returnB() I'm asking to return a pointer; since a pointer points to an address, the reason why returnB() works is because I'm returning &b?
In returnC() I'm asking for an address of int to be returned. When I return c is the & operator automatically "appended" c?
In returnC2() I'm asking again for an address of int to be returned. Does *d work because pointers point to an address?
Assume a, b, c are initialized as integers as Global.
Can someone validate if I am correct with all four of my questions?
Although Peter answered your question, one thing that's clearly confusing you is the symbols * and &. The tough part about getting your head around these is that they both have two different meanings that have to do with indirection (even excluding the third meanings of * for multiplication and & for bitwise-and).
*, when used as part of a type
indicates that the type is a pointer:
int is a type, so int* is a
pointer-to-int type, and int** is a
pointer-to-pointer-to-int type.
& when used as part of a type indicates that the type is a reference. int is a type, so int& is a reference-to-int (there is no such thing as reference-to-reference). References and pointers are used for similar things, but they are quite different and not interchangable. A reference is best thought of as an alias, or alternate name, for an existing variable. If x is an int, then you can simply assign int& y = x to create a new name y for x. Afterwords, x and y can be used interchangeably to refer to the same integer. The two main implications of this are that references cannot be NULL (since there must be an original variable to reference), and that you don't need to use any special operator to get at the original value (because it's just an alternate name, not a pointer). References can also not be reassigned.
* when used as a unary operator performs an operation called dereference (which has nothing to do with reference types!). This operation is only meaningful on pointers. When you dereference a pointer, you get back what it points to. So, if p is a pointer-to-int, *p is the int being pointed to.
& when used as a unary operator performs an operation called address-of. That's pretty self-explanatory; if x is a variable, then &x is the address of x. The address of a variable can be assigned to a pointer to the type of that variable. So, if x is an int, then &x can be assigned to a pointer of type int*, and that pointer will point to x. E.g. if you assign int* p = &x, then *p can be used to retrieve the value of x.
So remember, the type suffix & is for references, and has nothing to do with the unary operatory &, which has to do with getting addresses for use with pointers. The two uses are completely unrelated. And * as a type suffix declares a pointer, while * as a unary operator performs an action on pointers.
In returnA() I'm asking to return a pointer; just to clarify this works because j is a pointer?
Yes, int *j = &a initializes j to point to a. Then you return the value of j, that is the address of a.
In returnB() I'm asking to return a pointer; since a pointer points to an address, the reason why returnB() works is because I'm returning &b?
Yes. Here the same thing happens as above, just in a single step. &b gives the address of b.
In returnC() I'm asking for an address of int to be returned. When I return c is the & operator automatically appended?
No, it is a reference to an int which is returned. A reference is not an address the same way as a pointer is - it is just an alternative name for a variable. Therefore you don't need to apply the & operator to get a reference of a variable.
In returnC2() I'm asking again for an address of int to be returned. Does *d work because pointers point to an address?
Again, it is a reference to an int which is returned. *d refers to the original variable c (whatever that may be), pointed to by c. And this can implicitly be turned into a reference, just as in returnC.
Pointers do not in general point to an address (although they can - e.g. int** is a pointer to pointer to int). Pointers are an address of something. When you declare the pointer like something*, that something is the thing your pointer points to. So in my above example, int** declares a pointer to an int*, which happens to be a pointer itself.
Tyler, that was very helpful explanation, I did some experiment using visual studio debugger to clarify this difference even further:-
int sample = 90;
int& alias = sample;
int* pointerToSample = &sample;
Name Address Type
&alias 0x0112fc1c {90} int *
&sample 0x0112fc1c {90} int *
pointerToSample 0x0112fc1c {90} int *
*pointerToSample 90 int
alias 90 int &
&pointerToSample 0x0112fc04 {0x0112fc1c {90}} int * *
Memory Layout
PointerToSample Sample/alias
_______________......____________________
0x0112fc1c | | 90 |
___________|___.....__|________|_______...
[0x0112fc04] ... [0x0112fc1c
In returnC() and returnC2() you are not asking to return the address.
Both these functions return references to objects.
A reference is not the address of anything it is an alternative name of something (this may mean the compiler may (or may not depending on situation) use an address to represent the object (alternatively it may also know to keep it in register)).
All you know that a reference points at a specific object.
While a reference itself is not an object just an alternative name.
All of your examples produce undefined run-time behavior. You are returning pointers or references to items that disappear after execution leaves the function.
Let me clarify:
int * returnA()
{
static int a; // The static keyword keeps the variable from disappearing.
int * j = 0; // Declare a pointer to an int and initialize to location 0.
j = &a; // j now points to a.
return j; // return the location of the static variable (evil).
}
In your function, the variable j is assigned to point to a's temporary location. Upon exit of your function the variable a disappears, but it's former location is returned via j. Since a no longer exists at the location pointed to by j, undefined behavior will happen with accessing *j.
Variables inside functions should not be modified via reference or pointer by other code. It can happen although it produces undefined behavior.
Being pedantic, the pointers returned should be declared as pointing to constant data. The references returned should be const:
const char * Hello()
{
static const char text[] = "Hello";
return text;
}
The above function returns a pointer to constant data. Other code can access (read) the static data but cannot be modified.
const unsigned int& Counter()
{
static unsigned int value = 0;
value = value + 1;
return value;
}
In the above function, the value is initialized to zero on the first entry. All next executions of this function cause value to be incremented by one. The function returns a reference to a constant value. This means that other functions can use the value (from afar) as if it was a variable (without having to dereference a pointer).
In my thinking, a pointer is used for an optional parameter or object. A reference is passed when the object must exist. Inside the function, a referenced parameter means that the value exists, however a pointer must be checked for null before dereferencing it. Also, with a reference, there is more guarantee that the target object is valid. A pointer could point to an invalid address (not null) and cause undefined behavior.
Semantically, references do act as addresses. However, syntactically, they are the compiler's job, not yours, and you can treat a reference as if it is the original object it points to, including binding other references to it and having them refer to the original object too. Say goodbye to pointer arithmetic in this case.
The downside of that is that you can't modify what they refer to - they are bound at construct time.