Consider the following piece of code:
struct foo {
static constexpr const void* ptr = reinterpret_cast<const void*>(0x1);
};
auto main() -> int {
return 0;
}
The above example compiles fine in g++ v4.9 (Live Demo), while it fails to compile in clang v3.4 (Live Demo) and generates the following error:
error: constexpr variable 'ptr' must be initialized by a constant expression
Questions:
Which of the two compilers is right according to the standard?
What's the proper way of declaring an expression of such kind?
TL;DR
clang is correct, this is known gcc bug. You can either use intptr_t instead and cast when you need to use the value or if that is not workable then both gcc and clang support a little documented work-around that should allow your particular use case.
Details
So clang is correct on this one if we go to the draft C++11 standard section 5.19 Constant expressions paragraph 2 says:
A conditional-expression is a core constant expression unless it
involves one of the following as a potentially evaluated subexpression
[...]
and includes the following bullet:
— a reinterpret_cast (5.2.10);
One simple solution would be to use intptr_t:
static constexpr intptr_t ptr = 0x1;
and then cast later on when you need to use it:
reinterpret_cast<void*>(foo::ptr) ;
It may be tempting to leave it at that but this story gets more interesting though. This is know and still open gcc bug see Bug 49171: [C++0x][constexpr] Constant expressions support reinterpret_cast. It is clear from the discussion that gcc devs have some clear use cases for this:
I believe I found a conforming usage of reinterpret_cast in constant
expressions useable in C++03:
//---------------- struct X { X* operator&(); };
X x[2];
const bool p = (reinterpret_cast<X*>(&reinterpret_cast<char&>(x[1]))
- reinterpret_cast<X*>(&reinterpret_cast<char&>(x[0]))) == sizeof(X);
enum E { e = p }; // e should have a value equal to 1
//----------------
Basically this program demonstrates the technique, the C++11 library
function addressof is based on and thus excluding reinterpret_cast
unconditionally from constant expressions in the core language would render this useful program invalid and would make it impossible to
declare addressof as a constexpr function.
but were not able to get an exception carved for these use cases, see closed issues 1384:
Although reinterpret_cast was permitted in address constant
expressions in C++03, this restriction has been implemented in some
compilers and has not proved to break significant amounts of code. CWG
deemed that the complications of dealing with pointers whose tpes
changed (pointer arithmetic and dereference could not be permitted on
such pointers) outweighed the possible utility of relaxing the current
restriction.
BUT apparently gcc and clang support a little documented extension that allows constant folding of non-constant expressions using __builtin_constant_p (exp) and so the following expressions is accepted by both gcc and clang:
static constexpr const void* ptr =
__builtin_constant_p( reinterpret_cast<const void*>(0x1) ) ?
reinterpret_cast<const void*>(0x1) : reinterpret_cast<const void*>(0x1) ;
Finding documentation for this is near impossible but this llvm commit is informative with the following snippets provide for some interesting reading:
support the gcc __builtin_constant_p() ? ... : ... folding hack in C++11
and:
// __builtin_constant_p ? : is magical, and is always a potential constant.
and:
// This macro forces its argument to be constant-folded, even if it's not
// otherwise a constant expression.
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
We can find a more formal explanation of this feature in the gcc-patches email: C constant expressions, VLAs etc. fixes which says:
Furthermore, the rules for __builtin_constant_p calls as conditional
expression condition in the implementation are more relaxed than those
in the formal model: the selected half of the conditional expression
is fully folded without regard to whether it is formally a constant
expression, since __builtin_constant_p tests a fully folded argument
itself.
Clang is right. The result of a reinterpret-cast is never a constant expression (cf. C++11 5.19/2).
The purpose of constant expressions is that they can be reasoned about as values, and values have to be valid. What you're writing is not provably a valid pointer (since it's not the address of an object, or related to the address of an object by pointer arithmetic), so you're not allowed to use it as a constant expression. If you just want to store the number 1, store it as a uintptr_t and do the reinterpret cast at the use site.
As an aside, to elaborate a bit on the notion of "valid pointers", consider the following constexpr pointers:
constexpr int const a[10] = { 1 };
constexpr int * p1 = a + 5;
constexpr int const b[10] = { 2 };
constexpr int const * p2 = b + 10;
// constexpr int const * p3 = b + 11; // Error, not a constant expression
static_assert(*p1 == 0, ""); // OK
// static_assert(p1[5] == 0, ""); // Error, not a constant expression
static_assert(p2[-2] == 0, ""); // OK
// static_assert(p2[1] == 0, ""); // Error, "p2[1]" would have UB
static_assert(p2 != nullptr, ""); // OK
// static_assert(p2 + 1 != nullptr, ""); // Error, "p2 + 1" would have UB
Both p1 and p2 are constant expressions. But whether the result of pointer arithmetic is a constant expression depends on whether it is not UB! This kind of reasoning would be essentially impossible if you allowed the values of reinterpret_casts to be constant expressions.
I have also been running into this problem when programming for AVR microcontrollers. Avr-libc has header files (included through <avr/io.h> that make available the register layout for each microcontroller by defining macros such as:
#define TCNT1 (*(volatile uint16_t *)(0x84))
This allows using TCNT1 as if it were a normal variable and any reads and writes are directed to memory address 0x84 automatically. However, it also includes an (implicit) reinterpret_cast, which prevents using the address of this "variable" in a constant expression. And since this macro is defined by avr-libc, changing it to remove the cast is not really an option (and redefining such macros yourself works, but then requires defining them for all the different AVR chips, duplicating the info from avr-libc).
Since the folding hack suggested by Shafik here seems to no longer work in gcc 7 and above, I have been looking for another solution.
Looking at the avr-libc header files more closely, it turns out they have two modes:
Normally, they define variable-like macros as shown above.
When used inside the assembler (or when included with _SFR_ASM_COMPAT defined), they define macros that just contain the address, e.g.:
#define TCNT1 (0x84)
At first glance the latter seems useful, since you could then set _SFR_ASM_COMPAT before include <avr/io.h> and simply use intptr_t constants and use the address directly, rather than through a pointer. However, since you can include the avr-libc header only once (iow, only have TCNT1 as either a variable-like-macro, or an address), this trick only works inside a source file that does not include any other files that would need the variable-like-macros. In practice, this seems unlikely (though maybe you could have constexpr (class?) variables that are declared in a .h file and assigned a value in a .cpp file that includes nothing else?).
In any case, I found another trick by Krister Walfridsson, that defines these registers as external variables in a C++ header file and then defines them and locates them at a fixed location by using an assembler .S file. Then you can simply take the address of these global symbols, which is valid in a constexpr expressions. To make this work, this global symbol must have a different name as the original register macro, to prevent a conflict between both.
E.g. in your C++ code, you would have:
extern volatile uint16_t TCNT1_SYMBOL;
struct foo {
static constexpr volatile uint16_t* ptr = &TCNT1_SYMBOL;
};
And then you include a .S file in your project that contains:
#include <avr/io.h>
.global TCNT1_SYMBOL
TCNT1_SYMBOL = TCNT1
While writing this, I realized the above is not limited to the AVR-libc case, but can also be applied to the more generic question asked here. In that case, you could get a C++ file that looks like:
extern char MY_PTR_SYMBOL;
struct foo {
static constexpr const void* ptr = &MY_PTR_SYMBOL;
};
auto main() -> int {
return 0;
}
And a .S file that looks like:
.global MY_PTR_SYMBOL
MY_PTR_SYMBOL = 0x1
Here's how this looks: https://godbolt.org/z/vAfaS6 (I could not figure out how to get the compiler explorer to link both the cpp and .S file together, though
This approach has quite a bit more boilerplate, but does seem to work reliably across gcc and clang versions. Note that this approach looks like a similar approach using linker commandline options or linker scripts to place symbols at a certain memory address, but that approach is highly non-portable and tricky to integrate in a build process, while the approach suggested above is more portable and just a matter of adding a .S file into the build.
As pointed out in the comments, there is a performance downside though: The address is no more known at compile time. This means the compiler can no more use IN, OUT, SBI, CBI, SBIC, SBIS instructions. This increases code size, makes code slower, increases register pressure and many sequences are no more atomic, hence will need extra code if atomic execution is needed (most of the cases).
This is not a universal answer, but it works with that special case of a struct with special function registers of an MCU peripheral at fixed address. A union could be used to convert integer to pointer. It is still undefined behavior, but this cast-by-union is widely used in an embedded area. And it works perfectly in GCC (tested up to 9.3.1).
struct PeripheralRegs
{
volatile uint32_t REG_A;
volatile uint32_t REG_B;
};
template<class Base, uintptr_t Addr>
struct SFR
{
union
{
uintptr_t addr;
Base* regs;
};
constexpr SFR() :
addr(Addr) {}
Base* operator->() const
{
return regs;
}
void wait_for_something() const
{
while (!regs->REG_B);
}
};
constexpr SFR<PeripheralRegs, 0x10000000> peripheral;
uint32_t fn()
{
peripheral.wait_for_something();
return peripheral->REG_A;
}
Related
Consider the following piece of code:
struct foo {
static constexpr const void* ptr = reinterpret_cast<const void*>(0x1);
};
auto main() -> int {
return 0;
}
The above example compiles fine in g++ v4.9 (Live Demo), while it fails to compile in clang v3.4 (Live Demo) and generates the following error:
error: constexpr variable 'ptr' must be initialized by a constant expression
Questions:
Which of the two compilers is right according to the standard?
What's the proper way of declaring an expression of such kind?
TL;DR
clang is correct, this is known gcc bug. You can either use intptr_t instead and cast when you need to use the value or if that is not workable then both gcc and clang support a little documented work-around that should allow your particular use case.
Details
So clang is correct on this one if we go to the draft C++11 standard section 5.19 Constant expressions paragraph 2 says:
A conditional-expression is a core constant expression unless it
involves one of the following as a potentially evaluated subexpression
[...]
and includes the following bullet:
— a reinterpret_cast (5.2.10);
One simple solution would be to use intptr_t:
static constexpr intptr_t ptr = 0x1;
and then cast later on when you need to use it:
reinterpret_cast<void*>(foo::ptr) ;
It may be tempting to leave it at that but this story gets more interesting though. This is know and still open gcc bug see Bug 49171: [C++0x][constexpr] Constant expressions support reinterpret_cast. It is clear from the discussion that gcc devs have some clear use cases for this:
I believe I found a conforming usage of reinterpret_cast in constant
expressions useable in C++03:
//---------------- struct X { X* operator&(); };
X x[2];
const bool p = (reinterpret_cast<X*>(&reinterpret_cast<char&>(x[1]))
- reinterpret_cast<X*>(&reinterpret_cast<char&>(x[0]))) == sizeof(X);
enum E { e = p }; // e should have a value equal to 1
//----------------
Basically this program demonstrates the technique, the C++11 library
function addressof is based on and thus excluding reinterpret_cast
unconditionally from constant expressions in the core language would render this useful program invalid and would make it impossible to
declare addressof as a constexpr function.
but were not able to get an exception carved for these use cases, see closed issues 1384:
Although reinterpret_cast was permitted in address constant
expressions in C++03, this restriction has been implemented in some
compilers and has not proved to break significant amounts of code. CWG
deemed that the complications of dealing with pointers whose tpes
changed (pointer arithmetic and dereference could not be permitted on
such pointers) outweighed the possible utility of relaxing the current
restriction.
BUT apparently gcc and clang support a little documented extension that allows constant folding of non-constant expressions using __builtin_constant_p (exp) and so the following expressions is accepted by both gcc and clang:
static constexpr const void* ptr =
__builtin_constant_p( reinterpret_cast<const void*>(0x1) ) ?
reinterpret_cast<const void*>(0x1) : reinterpret_cast<const void*>(0x1) ;
Finding documentation for this is near impossible but this llvm commit is informative with the following snippets provide for some interesting reading:
support the gcc __builtin_constant_p() ? ... : ... folding hack in C++11
and:
// __builtin_constant_p ? : is magical, and is always a potential constant.
and:
// This macro forces its argument to be constant-folded, even if it's not
// otherwise a constant expression.
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
We can find a more formal explanation of this feature in the gcc-patches email: C constant expressions, VLAs etc. fixes which says:
Furthermore, the rules for __builtin_constant_p calls as conditional
expression condition in the implementation are more relaxed than those
in the formal model: the selected half of the conditional expression
is fully folded without regard to whether it is formally a constant
expression, since __builtin_constant_p tests a fully folded argument
itself.
Clang is right. The result of a reinterpret-cast is never a constant expression (cf. C++11 5.19/2).
The purpose of constant expressions is that they can be reasoned about as values, and values have to be valid. What you're writing is not provably a valid pointer (since it's not the address of an object, or related to the address of an object by pointer arithmetic), so you're not allowed to use it as a constant expression. If you just want to store the number 1, store it as a uintptr_t and do the reinterpret cast at the use site.
As an aside, to elaborate a bit on the notion of "valid pointers", consider the following constexpr pointers:
constexpr int const a[10] = { 1 };
constexpr int * p1 = a + 5;
constexpr int const b[10] = { 2 };
constexpr int const * p2 = b + 10;
// constexpr int const * p3 = b + 11; // Error, not a constant expression
static_assert(*p1 == 0, ""); // OK
// static_assert(p1[5] == 0, ""); // Error, not a constant expression
static_assert(p2[-2] == 0, ""); // OK
// static_assert(p2[1] == 0, ""); // Error, "p2[1]" would have UB
static_assert(p2 != nullptr, ""); // OK
// static_assert(p2 + 1 != nullptr, ""); // Error, "p2 + 1" would have UB
Both p1 and p2 are constant expressions. But whether the result of pointer arithmetic is a constant expression depends on whether it is not UB! This kind of reasoning would be essentially impossible if you allowed the values of reinterpret_casts to be constant expressions.
I have also been running into this problem when programming for AVR microcontrollers. Avr-libc has header files (included through <avr/io.h> that make available the register layout for each microcontroller by defining macros such as:
#define TCNT1 (*(volatile uint16_t *)(0x84))
This allows using TCNT1 as if it were a normal variable and any reads and writes are directed to memory address 0x84 automatically. However, it also includes an (implicit) reinterpret_cast, which prevents using the address of this "variable" in a constant expression. And since this macro is defined by avr-libc, changing it to remove the cast is not really an option (and redefining such macros yourself works, but then requires defining them for all the different AVR chips, duplicating the info from avr-libc).
Since the folding hack suggested by Shafik here seems to no longer work in gcc 7 and above, I have been looking for another solution.
Looking at the avr-libc header files more closely, it turns out they have two modes:
Normally, they define variable-like macros as shown above.
When used inside the assembler (or when included with _SFR_ASM_COMPAT defined), they define macros that just contain the address, e.g.:
#define TCNT1 (0x84)
At first glance the latter seems useful, since you could then set _SFR_ASM_COMPAT before include <avr/io.h> and simply use intptr_t constants and use the address directly, rather than through a pointer. However, since you can include the avr-libc header only once (iow, only have TCNT1 as either a variable-like-macro, or an address), this trick only works inside a source file that does not include any other files that would need the variable-like-macros. In practice, this seems unlikely (though maybe you could have constexpr (class?) variables that are declared in a .h file and assigned a value in a .cpp file that includes nothing else?).
In any case, I found another trick by Krister Walfridsson, that defines these registers as external variables in a C++ header file and then defines them and locates them at a fixed location by using an assembler .S file. Then you can simply take the address of these global symbols, which is valid in a constexpr expressions. To make this work, this global symbol must have a different name as the original register macro, to prevent a conflict between both.
E.g. in your C++ code, you would have:
extern volatile uint16_t TCNT1_SYMBOL;
struct foo {
static constexpr volatile uint16_t* ptr = &TCNT1_SYMBOL;
};
And then you include a .S file in your project that contains:
#include <avr/io.h>
.global TCNT1_SYMBOL
TCNT1_SYMBOL = TCNT1
While writing this, I realized the above is not limited to the AVR-libc case, but can also be applied to the more generic question asked here. In that case, you could get a C++ file that looks like:
extern char MY_PTR_SYMBOL;
struct foo {
static constexpr const void* ptr = &MY_PTR_SYMBOL;
};
auto main() -> int {
return 0;
}
And a .S file that looks like:
.global MY_PTR_SYMBOL
MY_PTR_SYMBOL = 0x1
Here's how this looks: https://godbolt.org/z/vAfaS6 (I could not figure out how to get the compiler explorer to link both the cpp and .S file together, though
This approach has quite a bit more boilerplate, but does seem to work reliably across gcc and clang versions. Note that this approach looks like a similar approach using linker commandline options or linker scripts to place symbols at a certain memory address, but that approach is highly non-portable and tricky to integrate in a build process, while the approach suggested above is more portable and just a matter of adding a .S file into the build.
As pointed out in the comments, there is a performance downside though: The address is no more known at compile time. This means the compiler can no more use IN, OUT, SBI, CBI, SBIC, SBIS instructions. This increases code size, makes code slower, increases register pressure and many sequences are no more atomic, hence will need extra code if atomic execution is needed (most of the cases).
This is not a universal answer, but it works with that special case of a struct with special function registers of an MCU peripheral at fixed address. A union could be used to convert integer to pointer. It is still undefined behavior, but this cast-by-union is widely used in an embedded area. And it works perfectly in GCC (tested up to 9.3.1).
struct PeripheralRegs
{
volatile uint32_t REG_A;
volatile uint32_t REG_B;
};
template<class Base, uintptr_t Addr>
struct SFR
{
union
{
uintptr_t addr;
Base* regs;
};
constexpr SFR() :
addr(Addr) {}
Base* operator->() const
{
return regs;
}
void wait_for_something() const
{
while (!regs->REG_B);
}
};
constexpr SFR<PeripheralRegs, 0x10000000> peripheral;
uint32_t fn()
{
peripheral.wait_for_something();
return peripheral->REG_A;
}
I have a type T (for simplicity you may assume it's integral). I want to write some magic piece of code, after which I can use the identifier foo in any context in which I could use a value previous declared to have type T - with no necessary conversion. I also want decltype(T) to be T, and no less importantly - I want a guarantee that no space will ever be allocated for foo, it will only be relevant at compile time.
Is there a way to achieve this other than using #DEFINE? AFAICT, constexpr const isn't guaranteed to avoiding space allocation.
There is no way to do that, because standard does not force compilers to optimize anything. constexpr variables are very likely to be optimized if they are not odr-used.
If you can relax some of your requirements:
enum : T
{
foo = some_value
};
Altough you create new type here, std::underlying_type<> will evaluate to T and you can use it without conversions where T is expected (with usual integer conversion rules). It also does not require function calling syntax (a constexpr function would be probably the best way to avoid space allocation, but it forces you to change the syntax from T val = foo to T val = foo(), which may or may not be acceptable).
If writing a function is good enough, here is a minimal example:
struct T { int value; };
constexpr T foo() { return { 42 }; }
int main()
{
return foo().value;
}
Compiled with -std=c++17 -O3:
main:
mov eax, 42
ret
The following condition is met:
#include <type_traits>
static_assert(std::is_same_v<T, decltype(foo())>);
Just to be clear, there is no guarantee whatsoever that your compiler and linker will remove the foo code from the final assembly, this is only highly probable.
However, it is guaranteed than the definition of function foo will only impact, if it does, the executable size and not the allocated storage.
Consider the following piece of code:
struct foo {
static constexpr const void* ptr = reinterpret_cast<const void*>(0x1);
};
auto main() -> int {
return 0;
}
The above example compiles fine in g++ v4.9 (Live Demo), while it fails to compile in clang v3.4 (Live Demo) and generates the following error:
error: constexpr variable 'ptr' must be initialized by a constant expression
Questions:
Which of the two compilers is right according to the standard?
What's the proper way of declaring an expression of such kind?
TL;DR
clang is correct, this is known gcc bug. You can either use intptr_t instead and cast when you need to use the value or if that is not workable then both gcc and clang support a little documented work-around that should allow your particular use case.
Details
So clang is correct on this one if we go to the draft C++11 standard section 5.19 Constant expressions paragraph 2 says:
A conditional-expression is a core constant expression unless it
involves one of the following as a potentially evaluated subexpression
[...]
and includes the following bullet:
— a reinterpret_cast (5.2.10);
One simple solution would be to use intptr_t:
static constexpr intptr_t ptr = 0x1;
and then cast later on when you need to use it:
reinterpret_cast<void*>(foo::ptr) ;
It may be tempting to leave it at that but this story gets more interesting though. This is know and still open gcc bug see Bug 49171: [C++0x][constexpr] Constant expressions support reinterpret_cast. It is clear from the discussion that gcc devs have some clear use cases for this:
I believe I found a conforming usage of reinterpret_cast in constant
expressions useable in C++03:
//---------------- struct X { X* operator&(); };
X x[2];
const bool p = (reinterpret_cast<X*>(&reinterpret_cast<char&>(x[1]))
- reinterpret_cast<X*>(&reinterpret_cast<char&>(x[0]))) == sizeof(X);
enum E { e = p }; // e should have a value equal to 1
//----------------
Basically this program demonstrates the technique, the C++11 library
function addressof is based on and thus excluding reinterpret_cast
unconditionally from constant expressions in the core language would render this useful program invalid and would make it impossible to
declare addressof as a constexpr function.
but were not able to get an exception carved for these use cases, see closed issues 1384:
Although reinterpret_cast was permitted in address constant
expressions in C++03, this restriction has been implemented in some
compilers and has not proved to break significant amounts of code. CWG
deemed that the complications of dealing with pointers whose tpes
changed (pointer arithmetic and dereference could not be permitted on
such pointers) outweighed the possible utility of relaxing the current
restriction.
BUT apparently gcc and clang support a little documented extension that allows constant folding of non-constant expressions using __builtin_constant_p (exp) and so the following expressions is accepted by both gcc and clang:
static constexpr const void* ptr =
__builtin_constant_p( reinterpret_cast<const void*>(0x1) ) ?
reinterpret_cast<const void*>(0x1) : reinterpret_cast<const void*>(0x1) ;
Finding documentation for this is near impossible but this llvm commit is informative with the following snippets provide for some interesting reading:
support the gcc __builtin_constant_p() ? ... : ... folding hack in C++11
and:
// __builtin_constant_p ? : is magical, and is always a potential constant.
and:
// This macro forces its argument to be constant-folded, even if it's not
// otherwise a constant expression.
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
We can find a more formal explanation of this feature in the gcc-patches email: C constant expressions, VLAs etc. fixes which says:
Furthermore, the rules for __builtin_constant_p calls as conditional
expression condition in the implementation are more relaxed than those
in the formal model: the selected half of the conditional expression
is fully folded without regard to whether it is formally a constant
expression, since __builtin_constant_p tests a fully folded argument
itself.
Clang is right. The result of a reinterpret-cast is never a constant expression (cf. C++11 5.19/2).
The purpose of constant expressions is that they can be reasoned about as values, and values have to be valid. What you're writing is not provably a valid pointer (since it's not the address of an object, or related to the address of an object by pointer arithmetic), so you're not allowed to use it as a constant expression. If you just want to store the number 1, store it as a uintptr_t and do the reinterpret cast at the use site.
As an aside, to elaborate a bit on the notion of "valid pointers", consider the following constexpr pointers:
constexpr int const a[10] = { 1 };
constexpr int * p1 = a + 5;
constexpr int const b[10] = { 2 };
constexpr int const * p2 = b + 10;
// constexpr int const * p3 = b + 11; // Error, not a constant expression
static_assert(*p1 == 0, ""); // OK
// static_assert(p1[5] == 0, ""); // Error, not a constant expression
static_assert(p2[-2] == 0, ""); // OK
// static_assert(p2[1] == 0, ""); // Error, "p2[1]" would have UB
static_assert(p2 != nullptr, ""); // OK
// static_assert(p2 + 1 != nullptr, ""); // Error, "p2 + 1" would have UB
Both p1 and p2 are constant expressions. But whether the result of pointer arithmetic is a constant expression depends on whether it is not UB! This kind of reasoning would be essentially impossible if you allowed the values of reinterpret_casts to be constant expressions.
I have also been running into this problem when programming for AVR microcontrollers. Avr-libc has header files (included through <avr/io.h> that make available the register layout for each microcontroller by defining macros such as:
#define TCNT1 (*(volatile uint16_t *)(0x84))
This allows using TCNT1 as if it were a normal variable and any reads and writes are directed to memory address 0x84 automatically. However, it also includes an (implicit) reinterpret_cast, which prevents using the address of this "variable" in a constant expression. And since this macro is defined by avr-libc, changing it to remove the cast is not really an option (and redefining such macros yourself works, but then requires defining them for all the different AVR chips, duplicating the info from avr-libc).
Since the folding hack suggested by Shafik here seems to no longer work in gcc 7 and above, I have been looking for another solution.
Looking at the avr-libc header files more closely, it turns out they have two modes:
Normally, they define variable-like macros as shown above.
When used inside the assembler (or when included with _SFR_ASM_COMPAT defined), they define macros that just contain the address, e.g.:
#define TCNT1 (0x84)
At first glance the latter seems useful, since you could then set _SFR_ASM_COMPAT before include <avr/io.h> and simply use intptr_t constants and use the address directly, rather than through a pointer. However, since you can include the avr-libc header only once (iow, only have TCNT1 as either a variable-like-macro, or an address), this trick only works inside a source file that does not include any other files that would need the variable-like-macros. In practice, this seems unlikely (though maybe you could have constexpr (class?) variables that are declared in a .h file and assigned a value in a .cpp file that includes nothing else?).
In any case, I found another trick by Krister Walfridsson, that defines these registers as external variables in a C++ header file and then defines them and locates them at a fixed location by using an assembler .S file. Then you can simply take the address of these global symbols, which is valid in a constexpr expressions. To make this work, this global symbol must have a different name as the original register macro, to prevent a conflict between both.
E.g. in your C++ code, you would have:
extern volatile uint16_t TCNT1_SYMBOL;
struct foo {
static constexpr volatile uint16_t* ptr = &TCNT1_SYMBOL;
};
And then you include a .S file in your project that contains:
#include <avr/io.h>
.global TCNT1_SYMBOL
TCNT1_SYMBOL = TCNT1
While writing this, I realized the above is not limited to the AVR-libc case, but can also be applied to the more generic question asked here. In that case, you could get a C++ file that looks like:
extern char MY_PTR_SYMBOL;
struct foo {
static constexpr const void* ptr = &MY_PTR_SYMBOL;
};
auto main() -> int {
return 0;
}
And a .S file that looks like:
.global MY_PTR_SYMBOL
MY_PTR_SYMBOL = 0x1
Here's how this looks: https://godbolt.org/z/vAfaS6 (I could not figure out how to get the compiler explorer to link both the cpp and .S file together, though
This approach has quite a bit more boilerplate, but does seem to work reliably across gcc and clang versions. Note that this approach looks like a similar approach using linker commandline options or linker scripts to place symbols at a certain memory address, but that approach is highly non-portable and tricky to integrate in a build process, while the approach suggested above is more portable and just a matter of adding a .S file into the build.
As pointed out in the comments, there is a performance downside though: The address is no more known at compile time. This means the compiler can no more use IN, OUT, SBI, CBI, SBIC, SBIS instructions. This increases code size, makes code slower, increases register pressure and many sequences are no more atomic, hence will need extra code if atomic execution is needed (most of the cases).
This is not a universal answer, but it works with that special case of a struct with special function registers of an MCU peripheral at fixed address. A union could be used to convert integer to pointer. It is still undefined behavior, but this cast-by-union is widely used in an embedded area. And it works perfectly in GCC (tested up to 9.3.1).
struct PeripheralRegs
{
volatile uint32_t REG_A;
volatile uint32_t REG_B;
};
template<class Base, uintptr_t Addr>
struct SFR
{
union
{
uintptr_t addr;
Base* regs;
};
constexpr SFR() :
addr(Addr) {}
Base* operator->() const
{
return regs;
}
void wait_for_something() const
{
while (!regs->REG_B);
}
};
constexpr SFR<PeripheralRegs, 0x10000000> peripheral;
uint32_t fn()
{
peripheral.wait_for_something();
return peripheral->REG_A;
}
We just upgraded our compiler to gcc 4.6 and now we get some of these warnings. At the moment our codebase is not in a state to be compiled with c++0x and anyway, we don't want to run this in prod (at least not yet) - so I needed a fix to remove this warning.
The warnings occur typically because of something like this:
struct SomeDataPage
{
// members
char vData[SOME_SIZE];
};
later, this is used in the following way
SomeDataPage page;
new(page.vData) SomeType(); // non-trivial constructor
To read, update and return for example, the following cast used to happen
reinterpret_cast<SomeType*>(page.vData)->some_member();
This was okay with 4.4; in 4.6 the above generates:
warning: type punned pointer will break strict-aliasing rules
Now a clean way to remove this error is to use a union, however like I said, we can't use c++0x (and hence unrestricted unions), so I've employed the horrible hack below - now the warning has gone away, but am I likely to invoke nasal daemons?
static_cast<SomeType*>(reinterpret_cast<void*>(page.vData))->some_member();
This appears to work okay (see simple example here: http://www.ideone.com/9p3MS) and generates no warnings, is this okay(not in the stylistic sense) to use this till c++0x?
NOTE: I don't want to use -fno-strict-aliasing generally...
EDIT: It seems I was mistaken, the same warning is there on 4.4, I guess we only picked this up recently with the change (it was always unlikely to be a compiler issue), the question still stands though.
EDIT: further investigation yielded some interesting information, it seems that doing the cast and calling the member function in one line is what is causing the warning, if the code is split into two lines as follows
SomeType* ptr = reinterpret_cast<SomeType*>(page.vData);
ptr->some_method();
this actually does not generate a warning. As a result, my simple example on ideone is flawed and more importantly my hack above does not fix the warning, the only way to fix it is to split the function call from the cast - then the cast can be left as a reinterpret_cast.
SomeDataPage page;
new(page.vData) SomeType(); // non-trivial constructor
reinterpret_cast<SomeType*>(page.vData)->some_member();
This was okay with 4.4; in 4.6 the above generates:
warning: type punned pointer will break strict-aliasing rules
You can try:
SomeDataPage page;
SomeType *data = new(page.vData) SomeType(); // non-trivial constructor
data->some_member();
Why not use:
SomeType *item = new (page.vData) SomeType();
and then:
item->some_member ();
I don't think a union is the best way, it may also be problematic. From the gcc docs:
`-fstrict-aliasing'
Allows the compiler to assume the strictest aliasing rules
applicable to the language being compiled. For C (and C++), this
activates optimizations based on the type of expressions. In
particular, an object of one type is assumed never to reside at
the same address as an object of a different type, unless the
types are almost the same. For example, an `unsigned int' can
alias an `int', but not a `void*' or a `double'. A character type
may alias any other type.
Pay special attention to code like this:
union a_union {
int i;
double d;
};
int f() {
a_union t;
t.d = 3.0;
return t.i;
}
The practice of reading from a different union member than the one
most recently written to (called "type-punning") is common. Even
with `-fstrict-aliasing', type-punning is allowed, provided the
memory is accessed through the union type. So, the code above
will work as expected. However, this code might not:
int f() {
a_union t;
int* ip;
t.d = 3.0;
ip = &t.i;
return *ip;
}
How this relates to your problem is tricky to determine. I guess the compiler is not seeing the data in SomeType as the same as the data in vData.
I'd be more concerned about SOME_SIZE not being big enough, frankly. However, it is legal to alias any type with a char*. So simply doing reinterpret_cast<T*>(&page.vData[0]) should be just fine.
Also, I'd question this kind of design. Unless you're implementing boost::variant or something similar, there's not much reason to use it.
struct SomeDataPage
{
// members
char vData[SOME_SIZE];
};
This is problematic for aliasing/alignment reasons. For one, the alignment of this struct isn't necessarily the same as the type you're trying to pun inside it. You could try using GCC attributes to enforce a certain alignment:
struct SomeDataPage { char vData[SOME_SIZE] __attribute__((aligned(16))); };
Where alignment of 16 should be adequate for anything I've come across. Then again, the compiler still won't like your code, but it won't break if the alignment is good. Alternatively, you could use the new C++0x alignof/alignas.
template <class T>
struct DataPage {
alignof(T) char vData[sizeof(T)];
};
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
return A::B::b;
}
The above code compiles. However if you go by Effective C++ book by Scott Myers(pg 14);
We need a definition for a in addition to the declaration.
Can anyone explain why this is an exception?
C++ compilers allow static const integers (and integers only) to have their value specified at the location they are declared. This is because the variable is essentially not needed, and lives only in the code (it is typically compiled out).
Other variable types (such as static const char*) cannot typically be defined where they are declared, and require a separate definition.
For a tiny bit more explanation, realize that accessing a global variable typically requires making an address reference in the lower-level code. But your global variable is an integer whose size is this typically around the size of an address, and the compiler realizes it will never change, so why bother adding the pointer abstraction?
By really pedantic rules, yes, your code needs a definition for that static integer.
But by practical rules, and what all compilers implement because that's how the rules of C++03 are intended - no, you don't need a definition.
The rules for such static constant integers are intended to allow you to omit the definition if the integer is used only in such situations where a value is immediately read, and if the static member can be used in constant expressions.
In your return statement, the value of the member is immediately read, so you can omit the definition of the static constant integer member if that's the only use of it. The following situation needs a definition, however:
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
int *p = &A::B::b;
}
No value is read here - but instead the address of it is taken. Therefore, the intent of the C++03 Standard is that you have to provide a definition for the member like the following in some implementation file.
const int A::B::b;
Note that the actual rules appearing in the C++03 Standard says that a definition is not required only where the variable is used where a constant expression is required. That rule, however, if strictly applied, is too strict. It would only allow you to omit a definition for situation like array-dimensions - but would require a definition in cases like a return statement. The corresponding defect report is here.
The wording of C++0x has been updated to include that defect report resolution, and to allow your code as written.
However, if you try the ternary operand without "defining" static consts, you get a linker error in GCC 4x:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795
So, although constructs like int k = A::CONSTVAL; are illegal in the current standard, they are supported. But the ternary operand is not. Some operators are more equal than others, if you get my drift :)
So much for "lax" rules. I suggest you write code conforming to the standard if you do not want surprises.
In general, most (and recent) C++ compilers allow static const ints
You just lucky, perhaps not. Try older compiler, such as gcc 2.0 and it will vehemently punish you with-less-than-pretty error message.