Pointer casting:can the Pointer has value? - c++

can the Pointer have value??
so In which case is it used
int num=100;
int* iptr=NULL;
iptr=reinterpret_cast<int*>(num);
printf("%d \n",num);
printf("%d \n",num);
result
100
100

Mappings between pointers and integers are implementation-defined.
Conversion of an integer to a pointer using reinterpret_cast will not be a safely-derived pointer value except under certain conditions. Those conditions are not met in your example.
Citation from CPP draft (N4713):
8.5.1.10 Reinterpret cast
...
6. A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined. [ Note:
Except as described in 6.6.4.4.3, the result of such a conversion will not be a safely-derived pointer value.
—end note ]
The conditions for Safely-derived pointers.
6.6.4.4.3 Safely-derived pointers
...
2 A pointer value is a safely-derived pointer to a dynamic object only if it has an object pointer type and it is one of the following:
(2.1) — the value returned by a call to the C++ standard library implementation of ::operator new(std::size_t) or ::operator new(std::size_t, std::align_val_t);
(2.2) — the result of taking the address of an object (or one of its subobjects) designated by an lvalue resulting from indirection through a safely-derived pointer value;
(2.3) — the result of well-defined pointer arithmetic using a safely-derived pointer value;
(2.4) — the result of a well-defined pointer conversion of a safely-derived pointer value;
(2.5) — the result of a reinterpret_cast of a safely-derived pointer value;
(2.6) — the result of a reinterpret_cast of an integer representation of a safely-derived pointer value;
(2.7) — the value of an object whose value was copied from a traceable pointer object, where at the time of the copy the source object contained a copy of a safely-derived pointer value.

Related

Is it UB to access a member by casting an object pointer to `char *`, then doing `*(member_type*)(pointer + offset)`?

Here's an example:
#include <cstddef>
#include <iostream>
struct A
{
char padding[7];
int x;
};
constexpr int offset = offsetof(A, x);
int main()
{
A a;
a.x = 42;
char *ptr = (char *)&a;
std::cout << *(int *)(ptr + offset) << '\n'; // Well-defined or not?
}
I always assumed that it's well-defined (otherwise what would be the point of offsetof), but wasn't sure.
Recently I was told that it's in fact UB, so I want to figure it out once and for all.
Does the example above cause UB or not? If you modify the class to not be standard-layout, does it affect the result?
And if it's UB, are there any workarounds for it (e.g. applying std::launder)?
This entire topic seems to be moot and underspecified.
Here's some information I was able to find:
Is adding to a “char *” pointer UB, when it doesn't actually point to a char array? - In 2011, CWG confirmed that we're allowed to examine the representation of a standard-layout object through an unsigned char pointer.
Unclear if a char pointer can be used insteaed, common sense says it can.
Unclear if staring from C++17 std::launder needs to be applied to the result of the (unsigned char *) cast. Given that it would be a breaking change, it's probably unnecessarly, at least in practice.
Unclear why C++17 changed offsetof to conditionally-support non-standard-layout types (used to be UB). It seems to imply that if an implementation supports that, then it also lets you examine the representation of non-standard-layout objects through unsigned char *.
Do we need to use std::launder when doing pointer arithmetic within a standard-layout object (e.g., with offsetof)? - A question similar to this one. No definitive answer was given.
Here I will refer to C++20 (draft) wording, because one relevant editorial issue was fixed between C++17 and C++20 and also it is possible to refer to specific sentences in HTML version of the C++20 draft, but otherwise there is nothing new in comparison to C++17.
At first, definitions of pointer values [basic.compound]/3:
Every value of pointer type is one of the following:
— a pointer to an object or function (the pointer is said to point to the object or function), or
— a pointer past the end of an object ([expr.add]), or
— the null pointer value for that type, or
— an invalid pointer value.
Now, lets see what happens in the (char *)&a expression.
Let me not prove that a is an lvalue denoting the object of type A, and I will say «the object a» to refer to this object.
The meaning of the &a subexpression is covered in [expr.unary.op]/(3.2):
if the operand is an lvalue of type T, the resulting expression is a prvalue of type “pointer to T” whose result is a pointer to the designated object
So, &a is a prvalue of type A* with the value «pointer to (the object) a».
Now, the cast in (char *)&a is equivalent to reinterpret_cast<char*>(&a), which is defined as static_cast<char*>(static_cast<void*>(&a)) ([expr.reinterpret.cast]/7).
Cast to void* doesn't change the pointer value ([conv.ptr]/2):
A prvalue of type “pointer to cv T”, where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The pointer value ([basic.compound]) is unchanged by this conversion.
i.e. it is still «pointer to (the object) a».
[expr.static.cast]/13 covers the outer static_cast<char*>(...):
A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.
If the original pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement of T, then the resulting pointer value is unspecified.
Otherwise, if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible with a, the result is a pointer to b.
Otherwise, the pointer value is unchanged by the conversion.
There is no object of type char which is pointer-interconvertible with the object a ([basic.compound]/4):
Two objects a and b are pointer-interconvertible if:
— they are the same object, or
— one is a union object and the other is a non-static data member of that object ([class.union]), or
— one is a standard-layout class object and the other is the first non-static data member of that object, or, if the object has no non-static data members, any base class subobject of that object ([class.mem]), or
— there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-interconvertible.
which means that the static_cast<char*>(...) doesn't change the pointer value and it is the same as in its operand, namely: «pointer to a».
So, (char *)&a is a prvalue of type char* whose value is «pointer to a». This value is stored into char* ptr variable. Then, when you try to do pointer arithmetic with such a value, namely ptr + offset, you step into [expr.add]/6:
For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T and the array element type are not similar, the behavior is undefined.
For the purposes of pointer arithmetic, the object a is considered to be an element of an array A[1] ([basic.compound]/3), so the array element type is A, the type of the pointer expression P is «pointer to char», char and A are not similar types (see [conv.qual]/2), so the behavior is undefined.
This question, and the other one about launder, both seem to me to boil down to interpretation of the last sentence of C++17 [expr.static.cast]/13, which covers what happens for static_cast<T *> applied to an operand of pointer to unrelated type which is correctly aligned:
A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T ”,
[...]
Otherwise, the pointer value is unchanged by the conversion.
Some posters appear to take this to mean that the result of the cast cannot point to an object of type T, and consequently that reinterpret_cast with pointers or references can only be used on pointer-interconvertible types.
But I don't see that as justified, and (this is a reductio ad absurdum argument) that position would also imply:
The resolution to CWG1314 is overturned.
Inspecting any byte of a standard-layout object is not possible (since casting to unsigned char * or whatever character type supposedly cannot be used to access that byte).
The strict aliasing rule would be redundant since the only way to actually achieve such aliasing is to use such casts.
There would be no normative text to justify the note "[Note: Converting a prvalue of type “pointer to T1 ” to the type “pointer to T2 ” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. —end note ]"
offsetof is useless (and the C++17 changes to it were therefore redundant)
It seems like a more sensible interpretation to me that this sentence means the result of the cast points to the same byte in memory as the operand. (As opposed to pointing to some other byte, as can happen for some pointer casts not covered by this sentence). Saying "the value is unchanged" does not mean "the type is unchanged", e.g. we describe conversion from int to long as preserving the value.
Also, I guess this may be controversial to some but I am taking as axiomatic that if a pointer's value is the address of an object, then the pointer points to that object, unless the Standard specifically excludes the case.
This is consistent with the text of [basic.compound]/3 which says the converse, i.e. that if a pointer points to an object, then its value is the address of the object.
There doesn't seem to be any other explicit statement defining when a pointer can or cannot be said to point to an object, but basic.compound/3 says that all pointers must be one of four cases (points to an object, points past the end, null, invalid).
Examples of excluded cases include:
The use case of std::launder specifically addresses a situation where there was such language ruling out the use of the un-laundered pointer.
A past-the-end pointer does not point to an object. (basic.compound/3)

Assign memory address stored in int to int

Assuming the value of uint32_t x is an address. How can I get the value behind this address?
My try was to simply assign the address to a pointer.
int*y = x;
But x is not an int pointer, it's just int with an address as value.
An integer type which is large enough to represent all data pointers can be converted into a pointer using reinterpret_cast or an explicit conversion. The pointer can be indirected to get the pointed value using the indirection operator.
Note that uint32_t is not guaranteed to be large enough to be able to represent all pointer values (and in fact will not be enough on modern 64 bit cpus). uintptr_t is meant precisely for this purpose.
Note that if the pointed address does not contain an object (of compatible type), then behaviour will be undefined.
In C++ this can be done using reinterpret_cast
8.5.1.10 Reinterpret cast [expr.reinterpret.cast]
...
5. A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined. [Note: Except as described in 6.6.4.4.3, the result of such a conversion will not be a safely-derived pointer value. —end note]
And the rules in 6.6.4.4.3 state:
An integer value is an integer representation of a safely-derived pointer only if its type is at least as large as std::intptr_t and it is one of the following:
—(3.1) the result of a reinterpret_cast of a safely-derived pointer value;
—(3.2) the result of a valid conversion of an integer representation of a safely-derived pointer value;
—(3.3) the value of an object whose value was copied from a traceable pointer object, where at the time of the copy the source object contained an integer representation of a safely-derived pointer value;
—(3.4) the result of an additive or bitwise operation, one of whose operands is an integer representation of a safely-derived pointer value P, if that result converted by reinterpret_cast<void*> would compare equal to a safely-derived pointer computable from reinterpret_cast<void*>(P).
So if x (in the question) has a type at least as large as std::intptr_t and is already an integral representation of a safely derived pointer as per the rules above, you will be able to get the value behind the address stored in x.

Can the NULL macro actually be a nullptr?

According to the draft of the standard N4713 (7.11/1):
A null pointer constant is an integer literal (5.13.2) with value zero or a prvalue of type std::nullptr_t.
and 21.2.3/2:
The macro NULL is an implementation-defined null pointer constant.
follow that NULL can be defined as nullptr. Same is mentioned on cppreference:
#define NULL 0
//since C++11
#define NULL nullptr
At the same time "Additive operators" clause says (8.5.6/7):
If the value 0 is added to or subtracted from a null pointer value, the result is a null pointer value. If two null
pointer values are subtracted, the result compares equal to the value 0 converted to the type std::ptrdiff_t.
Hence the following code should be valid:
0 + nullptr;
nullptr - nullptr;
but because of the lack of +/- operators for std::nullptr_t the code is invalid.
Is there something that I didn't take into account or NULL macro can't be actually defined as nullptr?
While nullptr is a null pointer constant, it is not a null pointer value. The latter is a value of some pointer type, which std::nullptr_t is not.
Reference:
A null pointer constant is an integer literal (5.13.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is
distinguishable from every other value of object pointer or function pointer type. Such a conversion is called
a null pointer conversion. [...]
7.11/1 in N4659, emphasize mine
So NULL can indeed be nullptr without providing the arithmetic operators.
nullptr is a null pointer literal, and although the result of converting nullptr to a pointer type is the null pointer value, nullptr itself isn't of a pointer type, but of type std::nullptr_t. The arithmetic works if you do convert the nullptr to a pointer type:
0 + (int*)nullptr;
(int*)nullptr - (int*)nullptr;
Can the NULL macro actually be a nullptr?
Yes, because nullptr is a null pointer literal.
Note that prior to C++11, the all of the null pointer literals in C++ happened to also be integer literals, so this bad code: char c = NULL; used to work in practice. If NULL is defined as nullptr, that code no longer works.
The keyword nullptr denotes the pointer literal. It is a prvalue of type std::nullptr_t. There exist implicit conversions from nullptr to null pointer value of any pointer type and any pointer to member type.
nullptr itself is not a pointer value nor pointer. Thus arithmetic operations are not applicable to nullptr.
For addition, either both operands shall have arithmetic or unscoped enumeration type, or one operand shall be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration type.
For subtraction, one of the following shall hold:
(2.1) both operands have arithmetic or unscoped enumeration type; or
(2.2) both operands are pointers to cv-qualified or cv-unqualified versions of the same completely-defined object type; or
(2.3) the left operand is a pointer to a completely-defined object type and the right operand has integral or unscoped enumeration type.
std::nullptr_t is none of those, hence std::nullptr cannot participate in additive operations.
Note that not even all pointer values can participate. For example, function pointer values and void pointer values cannot, even though either can be a null pointer value.

Integer representation of pointer

What is the integer representation of pointer?
A pointer value is a safely-derived pointer to a dynamic object only
if it has an object pointer type and it is one of the following:
[...]
— the result of a reinterpret_cast of an integer representation of a safely-derived pointer value;
[...]
My doubt is about the following:
Type int is less than any pointer to type. In particular, pointer to cannot be casted to int using reinterpret_cast.
The term is defined in the very next paragraph of the standard.
An integer value is an integer representation of a safely-derived pointer only if its type is at least as large as
std::intptr_t and it is one of the following:
— the result of a reinterpret_cast of a safely-derived pointer value;
— the result of a valid conversion of an integer representation of a safely-derived pointer value;
— the value of an object whose value was copied from a traceable pointer object, where at the time of
the copy the source object contained an integer representation of a safely-derived pointer value;
— the result of an additive or bitwise operation, one of whose operands is an integer representation of a
safely-derived pointer value P, if that result converted by reinterpret_cast<void*> would compare
equal to a safely-derived pointer computable from reinterpret_cast<void*>(P).

reinterpret_cast an iterator to a pointer

I've got an iterator of Things. If I want to convert the current item to a pointer to the item, why does this work:
thing_pointer = &(*it);
But this not:
thing_pointer = reinterpret_cast<Thing*>(it);
This is the compiler error I'm trying to comprehend: http://msdn.microsoft.com/en-us/library/sy5tsf8z(v=vs.90).aspx
Just in case, the type of the iterator is std::_Vector_iterator<std::_Vector_val<Thing,std::allocator<Thing> > >
In
&(*it);
the * is overloaded to do what you logically mean: convert the iterator type to its pointed-to object. You can then safely take the address of this object.
Whereas in
reinterpret_cast<Thing*>(it);
you are telling the compiler to literally reinterpret the it object as a pointer. But it might not be a pointer at all -- it might be a 50-byte struct, for all you know! In that case, the first sizeof (Thing*) bytes of it will absolutely not happen to point at anything sensible.
Tip: reinterpret_cast<> is nearly always the wrong thing.
Obligitory Standard Quotes, emphasis mine:
5.2.19 Reinterpret cast
1/ [...] Conversions that can be performed explicitly using
reinterpret_cast are listed below. No other conversion can be
performed explicitly using reinterpret_cast.
4/ A pointer can be explicitly converted to any integral type large
enough to hold it. [...]
5/ A value of integral type or enumeration type can be explicitly
converted to a pointer. [...]
6/ A function pointer can be explicitly converted to a function
pointer of a different type. [...]
7/ An object pointer can be explicitly converted to an object pointer
of a different type. [...]
8/ Converting a function pointer to an object pointer type or vice
versa is conditionally-supported. [...]
9/ The null pointer value (4.10) is converted to the null pointer
value of the destination type. [...]
10/ [...] “pointer to member of X of type T1” can be explicitly
converted to [...] “pointer to member of Y of type T2” [...]
11/ A [...] T1 can be cast to the type “reference to T2” if an
expression of type “pointer to T1” can be explicitly converted to the
type “pointer to T2” using a reinterpret_cast. [...]
With the exception of the integral-to-pointer and value-to-reference conversions noted in 4/, 5/ and 11/ the only conversions that can be performed using reinterpret_cast are pointer-to-pointer conversions.
However in:
thing_pointer = reinterpret_cast<Thing*>(it);
it is not a pointer, but an object. It just so happens that this object was designed to emulate a pointer in many ways, but it's still not a pointer.
Because * operator of iterator is overloaded and it return a
reference to the object it points on.
You can force it by thing_pointer = *(reinterpret_cast<Thing**>(&it));. But it's undefined behavior.
Because iterator is not a pointer. It is a class of implementation-defined structure, and if you try to reinterpret it to a pointer, the raw data of the iterator class will be taken as a memory pointer, which may, but probably will not point to valid memory
The first gets a reference to the object, then takes the address of it, giving the pointer.
The second tries to cast the iterator to a pointer, which is likely to fail because most types can't be cast to pointers - only other pointers, integers, and class types with a conversion operator.