How can I know how will reinterpret cast work on GCC compiler? Is it mentioned in the documentation? May I know any reference or link if it exist?
Reading the documentation in the standard it is very explicit about different types. But for the basic pointer we have:
A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined. [ Note: It is intended to be unsurprising to those who know the addressing structure of the underlying machine. — end note ] A value of type std::nullptr_t can be converted to an integral type; the conversion has the same meaning and validity as a conversion of (void*)0 to the integral type. [Note: A reinterpret_cast cannot be used to convert a value of any type to the type std::nullptr_t. — end note ]
For integers:
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 3.7.4.3, the result of such a conversion will not be a safely-derived pointer value. —endnote]
I have used reinterpret_cast many times with g++. In embedded programming, it's useful for mapping a struct that represents a peripheral's registers to its (fixed) address:
struct DEV_Registers
{
volatile uint32_t REGA;
volatile uint32_t REGB;
// ...
};
static DEV_Registers& DEV(*reinterpret_cast<DEV_Registers>(0x40000000));
This lets me write code like:
DEV.REGB = 0x12345678;
which does the right thing (set the register at 0x40000004 to the value 0x12345678) and is quite legible.
It's hard to tell if your question is asking for details beyond this.
Related
In C one can have string literals in the form of
char *string = "string here";
integer literals:
uint8_t num = 5;
long literals:
long long bigNum = 90322L;
floating point literals:
float decimal = 6.3f;
Is the a way to have a pointer literal? That is a literal address to a memory space. I am doing some work on an embedded project and need to hard code a value for a DMA access. I am doing something similar to the following:
uint32_t *source = 0x08000000;
While this compiles and works correctly I get the following compiler error (I'm using a variant of GCC):
cc0144: {D} warning: a value of type "int" cannot be used to initialize an entity of type "uint32_t *"
cc0152: {D} warning: conversion of nonzero integer to pointer
Is there a correct way to do this or do I just need to accept this as a fact of C? I know I can do:
uint32_t *source = (uint32_t *)0x08000000;
But that just seems very unnecessary. What is the industry way of doing this? I am also wondering if this feature exists in C++.
In both C and C++ the only pointer literal or constant is zero. We can go to the draft C99 standard section 6.3.2.3 Pointers:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
and:
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.56)
the correct way to deal with non-zero integer constant is to use a cast.
The equivalent section from the draft C++ standard would probably be section 5.2.10 Reinterpret cast which says:
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 3.7.4.3, the result of such a conversion will
not be a safely-derived pointer value. —end note ]
You need to see section 3.7.4.3 for all the details.
For the pointer literal reference you need section 2.14.7 Pointer literals which says:
The pointer literal is the keyword nullptr. It is a prvalue of type
std::nullptr_t. [ Note: std::nullptr_t is a distinct type that is
neither a pointer type nor a pointer to member type; rather, a prvalue
of this type is a null pointer constant and can be converted to a null
pointer value or null member pointer value. See 4.10 and 4.11. —end
note ]
No, it's not. That is because literals are valid values, and the only valid pointers are addresses of objects, i.e. the result of address-of operations or of pointer arithmetic on valid pointers.
You could argue that the nullptr keyword furnishes a kind of "pointer literal"; the C++ standard calls it that. It is however the only pointer literal, and ironically it is not of pointer type.
In C++ could you do something like the following?
uint32_t * source = reinterpret_cast<uint32_t*>(0x08000000);
In C one can have string literals in the form of
char *string = "string here";
integer literals:
uint8_t num = 5;
long literals:
long long bigNum = 90322L;
floating point literals:
float decimal = 6.3f;
Is the a way to have a pointer literal? That is a literal address to a memory space. I am doing some work on an embedded project and need to hard code a value for a DMA access. I am doing something similar to the following:
uint32_t *source = 0x08000000;
While this compiles and works correctly I get the following compiler error (I'm using a variant of GCC):
cc0144: {D} warning: a value of type "int" cannot be used to initialize an entity of type "uint32_t *"
cc0152: {D} warning: conversion of nonzero integer to pointer
Is there a correct way to do this or do I just need to accept this as a fact of C? I know I can do:
uint32_t *source = (uint32_t *)0x08000000;
But that just seems very unnecessary. What is the industry way of doing this? I am also wondering if this feature exists in C++.
In both C and C++ the only pointer literal or constant is zero. We can go to the draft C99 standard section 6.3.2.3 Pointers:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
and:
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.56)
the correct way to deal with non-zero integer constant is to use a cast.
The equivalent section from the draft C++ standard would probably be section 5.2.10 Reinterpret cast which says:
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 3.7.4.3, the result of such a conversion will
not be a safely-derived pointer value. —end note ]
You need to see section 3.7.4.3 for all the details.
For the pointer literal reference you need section 2.14.7 Pointer literals which says:
The pointer literal is the keyword nullptr. It is a prvalue of type
std::nullptr_t. [ Note: std::nullptr_t is a distinct type that is
neither a pointer type nor a pointer to member type; rather, a prvalue
of this type is a null pointer constant and can be converted to a null
pointer value or null member pointer value. See 4.10 and 4.11. —end
note ]
No, it's not. That is because literals are valid values, and the only valid pointers are addresses of objects, i.e. the result of address-of operations or of pointer arithmetic on valid pointers.
You could argue that the nullptr keyword furnishes a kind of "pointer literal"; the C++ standard calls it that. It is however the only pointer literal, and ironically it is not of pointer type.
In C++ could you do something like the following?
uint32_t * source = reinterpret_cast<uint32_t*>(0x08000000);
Is it just the reinterpret_cast?
int *pointer;
uintptr_t value;
value == reinterpret_cast<uintptr_t>(pointer);
Depends on your goal really.
[expr.reinterpret.cast]
4 A pointer can be explicitly converted to any integral type
large enough to hold it. The mapping function is
implementation-defined. [ Note: It is intended to be unsurprising to
those who know the addressing structure of the underlying machine.
— end note ] A value of type std::nullptr_t can be converted to an
integral type; the conversion has the same meaning and validity as a
conversion of (void*)0 to the integral type.
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.
The mapping is implementation defined (obviously). If you wish to check that the value of pointer was used to initialize value, then your check is insufficient. The above doesn't promise that reinterpret_cast<uintptr_t>(pointer) will always yield the same integer, even though all sane implementations today do.
I would do the check in reverse, since we have a round trip guarantee:
reinterpret_cast<int*>(value) == pointer;
But even then, it's a pretty weak guarantee. I would not faff about with these conversions too much if I were you. It may be worth to reconsider your design.
If you follow the standard to the letter, you ought to use
value == (uintptr_t)(void*)pointer
or using reinterpret_cast:
value == reinterpret_cast<uintptr_t>(reinterpret_cast<void*>(pointer))
which personally I find less readable. Naturally the compiler will remove all the "fluff".
In C one can have string literals in the form of
char *string = "string here";
integer literals:
uint8_t num = 5;
long literals:
long long bigNum = 90322L;
floating point literals:
float decimal = 6.3f;
Is the a way to have a pointer literal? That is a literal address to a memory space. I am doing some work on an embedded project and need to hard code a value for a DMA access. I am doing something similar to the following:
uint32_t *source = 0x08000000;
While this compiles and works correctly I get the following compiler error (I'm using a variant of GCC):
cc0144: {D} warning: a value of type "int" cannot be used to initialize an entity of type "uint32_t *"
cc0152: {D} warning: conversion of nonzero integer to pointer
Is there a correct way to do this or do I just need to accept this as a fact of C? I know I can do:
uint32_t *source = (uint32_t *)0x08000000;
But that just seems very unnecessary. What is the industry way of doing this? I am also wondering if this feature exists in C++.
In both C and C++ the only pointer literal or constant is zero. We can go to the draft C99 standard section 6.3.2.3 Pointers:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant.55)
and:
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.56)
the correct way to deal with non-zero integer constant is to use a cast.
The equivalent section from the draft C++ standard would probably be section 5.2.10 Reinterpret cast which says:
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 3.7.4.3, the result of such a conversion will
not be a safely-derived pointer value. —end note ]
You need to see section 3.7.4.3 for all the details.
For the pointer literal reference you need section 2.14.7 Pointer literals which says:
The pointer literal is the keyword nullptr. It is a prvalue of type
std::nullptr_t. [ Note: std::nullptr_t is a distinct type that is
neither a pointer type nor a pointer to member type; rather, a prvalue
of this type is a null pointer constant and can be converted to a null
pointer value or null member pointer value. See 4.10 and 4.11. —end
note ]
No, it's not. That is because literals are valid values, and the only valid pointers are addresses of objects, i.e. the result of address-of operations or of pointer arithmetic on valid pointers.
You could argue that the nullptr keyword furnishes a kind of "pointer literal"; the C++ standard calls it that. It is however the only pointer literal, and ironically it is not of pointer type.
In C++ could you do something like the following?
uint32_t * source = reinterpret_cast<uint32_t*>(0x08000000);
I have the following code:
void (* point)();
point=prova;
unsigned long int imm8 = point<<24;
...
void prova(){
...
}
The third line of code I have error:
invalid operands to binary << (have 'void (*)()' and 'int')
I'm trying to apply the shift operator to a function pointer, but I get the following error. how can I do?
I don't see why you want to do this but the error is correct, the draft C++ standard in section 5.8 Shift operators says;
The operands shall be of integral or unscoped enumeration type and integral promotions are performed.[...]
You can use reinterpret_cast to convert it to an integral type(uintptr_t) if needed. The linked reference contains the following example:
int i = 7;
// pointer to integer and back
uintptr_t v1 = reinterpret_cast<uintptr_t>(&i); // static_cast is an error
Warning
This type of conversion is only conditionally supported, we can see this from the C++ draft standard section 5.2.10 Reinterpret cast which says:
Converting a function pointer to an object pointer type or vice versa
is conditionally-supported. The meaning of such a conversion is
implementation-defined, except that if an implementation supports
conversions in both directions, converting a prvalue of one type to
the other type and back, possibly with different cv- qualification,
shall yield the original pointer value.
There is no portable way to do this.
The standard guarantees that you can convert a void* to uintptr_t without loss of information -- but it doesn't guarantee that uintptr_t exists. A conforming implementation might not have an integer type wide enough to hold a converted pointer without loss of information.
And even if uintptr_t exists, the language only guarantees that you can convert void* to uintptr_t without loss of information. A conforming permission might have, for example, 64-bit object pointers, 64-bit uintprt_t, and 128-bit function pointers.
It's likely, in most implementations, that you can convert a function pointer to uintptr_t without loss of information. (I think POSIX guarantees this, though the ISO C and C++ standards do not.)
Once you've done that, probably using a reinterpret_cast, you have an unsigned integer, which you can shift as you like.
The result of this shift will almost certainly be meaningless garbage. C++ doesn't prevent you from shooting yourself in the foot, which is what you appear to be trying to do.
There should be no valid reason for doing this. However, you can do this by first casting to unsigned long int
unsigned long int imm8 = reinterpret_cast<unsigned long int >(point)<<24;
Here reinterpret_cast is done to treat the pointer as unsigned long int. Note that it is not portable and has the possibility of data loss.