Determining struct member byte-offsets at compile-time? - c++

I want to find the byte offset of a struct member at compile-time. For example:
struct vertex_t
{
vec3_t position;
vec3_t normal;
vec2_t texcoord;
}
I would want to know that the byte offset to normal is (in this case it should be 12.)
I know that I could use offsetof, but that is a run-time function and I'd prefer not to use it.
Is what I'm trying to accomplish even possible?
EDIT: offsetof is compile-time, my bad!

offsetof is a compile time constant, if we look at the draft C++ standard section C.3 C standard library paragraph 2 says:
The C++ standard library provides 57 standard macros from the C library, as shown in Table 149.
and the table includes offsetof. If we go to the C99 draft standard section 7.17 Common definitions paragraph 3 includes:
offsetof(type, member-designator)
which expands to an integer constant expression that has type size_t, the value of
which is the offset in bytes [...]

In C:
offsetof is usually actually a macro, and due to its definition, it will probably optimized by the compiler so that it reduces to a constant value. And even if it does become an expression, it is small enough that it should cause almost no overhead.
For example, at the file stddef.h, it is defined as:
#define offsetof(st, m) ((size_t)(&((st *)0)->m))
In C++:
Things get a bit more complicated, since it must resolve offsets for members as methods and other variables. So offsetof is defined as a macro to call another method:
#define offsetof(st, m) __builtin_offsetof(st, m)
If you need it only for structs, you are good enough with offsetof. Else, I don't think it is possible.

Are you sure it is run-time?
The following works..
#include <iostream>
#include <algorithm>
struct vertex_t
{
int32_t position;
int32_t normal;
int32_t texcoord;
};
const int i = offsetof(vertex_t, normal); //compile time..
int main()
{
std::cout<<i;
}
Also see here: offsetof at compile time

Related

Cannot assign INVALID_HANDLE_VALUE to constexpr HANDLE when making typedefs for Winapi [duplicate]

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;
}

Clang won't compile anonymous struct [duplicate]

Some C++ compilers permit anonymous unions and structs as an extension to standard C++. It's a bit of syntactic sugar that's occasionally very helpful.
What's the rationale that prevents this from being part of the standard? Is there a technical roadblock? A philosophical one? Or just not enough of a need to justify it?
Here's a sample of what I'm talking about:
struct vector3 {
union {
struct {
float x;
float y;
float z;
};
float v[3];
};
};
My compiler will accept this, but it warns that "nameless struct/union" is a non-standard extension to C++.
As others have pointed out anonymous unions are permitted in standard C++, but anonymous structs are not.
The reason for this is that C supports anonymous unions but not anonymous structs*, so C++ supports the former for compatibility but not the latter because it's not needed for compatibility.
Furthermore, there's not much use to anonymous structs in C++. The use you demonstrate, to have a struct containing three floats which can be referred to either by .v[i], or .x, .y, and .z, I believe results in undefined behavior in C++. C++ does not allow you to write to one member of a union, say .v[1], and then read from another member, say .y. Although code that does this is not uncommon it is not actually well defined.
C++'s facilities for user-defined types provide alternative solutions. For example:
struct vector3 {
float v[3];
float &operator[] (int i) { return v[i]; }
float &x() { return v[0]; }
float &y() { return v[1]; }
float &z() { return v[2]; }
};
* C11 apparently adds anonymous structs, so a future revision to C++ may add them.
I'll say, you can clean up your vector3 declaration by just using a union
union vector3 {
struct { float x, y, z; } ;
float v[3] ;
} ;
Sure, anonymous structures was an MSVC extension. But ISO C11 permits it now, and gcc allows it, and so does Apple's llvm compiler.
Why in C11 and not C++11? I'm not sure, but practically speaking most (gcc++, MSVC++ and Apple's C++ compiler) C++ compilers support them.
Not sure what you mean. Section 9.5 of the C++ spec, clause 2:
A union of the form
union { member-specification } ;
is called an anonymous union; it defines an unnamed object of unnamed type.
You can do things like this too:
void foo()
{
typedef
struct { // unnamed, is that what you mean by anonymous?
int a;
char b;
} MyStructType; // this is more of a "C" style, but valid C++ nonetheless
struct { // an anonymous struct, not even typedef'd
double x;
double y;
} point = { 1.0, 3.4 };
}
Not always very useful... although sometimes useful in nasty macro definitions.
Unions can be anonymous; see the Standard, 9.5 paragraph 2.
What purpose do you see an anonymous struct or class as fulfilling? Before speculating why something isn't in the Standard, I'd like to have some idea why it should be, and I don't see a use for an anonymous struct.
Based on the edit, the comments, and this MSDN article: Anonymous Structures, I'll hazard a guess - it fits poorly with the concept of encapsulation. I wouldn't expect a member of a class to mess with my class namespace beyond merely adding one member. Furthermore, changes to the anonymous structure can affect my class without permission.
Your code
union {
struct {
float x;
float y;
float z;
};
float v[3];
};
is like
union Foo {
int;
float v[3];
};
which is surely invalid (in C99 and before).
The reason is probably to simplify parsing (in C), because in that case you only need to check that the struct/union body has only "declarator statements" like
Type field;
That said, gcc and "other compilers" supports unnamed fields as an extension.
Edit: Anonymous structs are now officially supported in C11 (§6.7.2.1/13).
Edit: I put up a non-answer since I didn't realize the difference between an "anonymous struct" and an "unnamed struct". Rather than delete this answer, I will just leave it up, but my response here is not correct.
Original response follows:
I don't see it mentioned in any of the answers here, I guess since they're mostly written from before the "modern C++" era, but since I found my way here via a google search on "C++ anonymous struct", I'll just put this answer down here:
I'm able to do the following:
struct /* no typename */
{
int i=2;
} g_some_object{};
int main()
{
return g_some_object.i;
}
I noticed this behavior is actually leveraged in some of the examples for C++20 coroutines on cppreference, particularly for demonstrating a task awaiter.
If at any point in the past this behavior was not allowed, then that's no longer the case--we can definitely do this now.

C++ constexpr does not work with reinterpret_cast [duplicate]

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;
}

constexpr and initialization of a static const void pointer with reinterpret cast, which compiler is right?

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;
}

What happens if I define a 0-size array in C/C++?

Just curious, what actually happens if I define a zero-length array int array[0]; in code? GCC doesn't complain at all.
Sample Program
#include <stdio.h>
int main() {
int arr[0];
return 0;
}
Clarification
I'm actually trying to figure out if zero-length arrays initialised this way, instead of being pointed at like the variable length in Darhazer's comments, are optimised out or not.
This is because I have to release some code out into the wild, so I'm trying to figure out if I have to handle cases where the SIZE is defined as 0, which happens in some code with a statically defined int array[SIZE];
I was actually surprised that GCC does not complain, which led to my question. From the answers I've received, I believe the lack of a warning is largely due to supporting old code which has not been updated with the new [] syntax.
Because I was mainly wondering about the error, I am tagging Lundin's answer as correct (Nawaz's was first, but it wasn't as complete) -- the others were pointing out its actual use for tail-padded structures, while relevant, isn't exactly what I was looking for.
An array cannot have zero size.
ISO 9899:2011 6.7.6.2:
If the expression is a constant expression, it shall have a value greater than zero.
The above text is true both for a plain array (paragraph 1). For a VLA (variable length array), the behavior is undefined if the expression's value is less than or equal to zero (paragraph 5). This is normative text in the C standard. A compiler is not allowed to implement it differently.
gcc -std=c99 -pedantic gives a warning for the non-VLA case.
As per the standard, it is not allowed.
However it's been current practice in C compilers to treat those declarations as a flexible array member (FAM) declaration:
C99 6.7.2.1, §16: As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.
The standard syntax of a FAM is:
struct Array {
size_t size;
int content[];
};
The idea is that you would then allocate it so:
void foo(size_t x) {
Array* array = malloc(sizeof(size_t) + x * sizeof(int));
array->size = x;
for (size_t i = 0; i != x; ++i) {
array->content[i] = 0;
}
}
You might also use it statically (gcc extension):
Array a = { 3, { 1, 2, 3 } };
This is also known as tail-padded structures (this term predates the publication of the C99 Standard) or struct hack (thanks to Joe Wreschnig for pointing it out).
However this syntax was standardized (and the effects guaranteed) only lately in C99. Before a constant size was necessary.
1 was the portable way to go, though it was rather strange.
0 was better at indicating intent, but not legal as far as the Standard was concerned and supported as an extension by some compilers (including gcc).
The tail padding practice, however, relies on the fact that storage is available (careful malloc) so is not suited to stack usage in general.
In Standard C and C++, zero-size array is not allowed..
If you're using GCC, compile it with -pedantic option. It will give warning, saying:
zero.c:3:6: warning: ISO C forbids zero-size array 'a' [-pedantic]
In case of C++, it gives similar warning.
It's totally illegal, and always has been, but a lot of compilers
neglect to signal the error. I'm not sure why you want to do this.
The one use I know of is to trigger a compile time error from a boolean:
char someCondition[ condition ];
If condition is a false, then I get a compile time error. Because
compilers do allow this, however, I've taken to using:
char someCondition[ 2 * condition - 1 ];
This gives a size of either 1 or -1, and I've never found a compiler
which would accept a size of -1.
Another use of zero-length arrays is for making variable-length object (pre-C99). Zero-length arrays are different from flexible arrays which have [] without 0.
Quoted from gcc doc:
Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure that is really a header for a variable-length object:
struct line {
int length;
char contents[0];
};
struct line *thisline = (struct line *)
malloc (sizeof (struct line) + this_length);
thisline->length = this_length;
In ISO C99, you would use a flexible array member, which is slightly different in syntax and semantics:
Flexible array members are written as contents[] without the 0.
Flexible array members have incomplete type, and so the sizeof operator may not be applied.
A real-world example is zero-length arrays of struct kdbus_item in kdbus.h (a Linux kernel module).
I'll add that there is a whole page of the online documentation of gcc on this argument.
Some quotes:
Zero-length arrays are allowed in GNU C.
In ISO C90, you would have to give contents a length of 1
and
GCC versions before 3.0 allowed zero-length arrays to be statically initialized, as if they were flexible arrays. In addition to those cases that were useful, it also allowed initializations in situations that would corrupt later data
so you could
int arr[0] = { 1 };
and boom :-)
Zero-size array declarations within structs would be useful if they were allowed, and if the semantics were such that (1) they would force alignment but otherwise not allocate any space, and (2) indexing the array would be considered defined behavior in the case where the resulting pointer would be within the same block of memory as the struct. Such behavior was never permitted by any C standard, but some older compilers allowed it before it became standard for compilers to allow incomplete array declarations with empty brackets.
The struct hack, as commonly implemented using an array of size 1, is dodgy and I don't think there's any requirement that compilers refrain from breaking it. For example, I would expect that if a compiler sees int a[1], it would be within its rights to regard a[i] as a[0]. If someone tries to work around the alignment issues of the struct hack via something like
typedef struct {
uint32_t size;
uint8_t data[4]; // Use four, to avoid having padding throw off the size of the struct
}
a compiler might get clever and assume the array size really is four:
; As written
foo = myStruct->data[i];
; As interpreted (assuming little-endian hardware)
foo = ((*(uint32_t*)myStruct->data) >> (i << 3)) & 0xFF;
Such an optimization might be reasonable, especially if myStruct->data could be loaded into a register in the same operation as myStruct->size. I know nothing in the standard that would forbid such optimization, though of course it would break any code which might expect to access stuff beyond the fourth element.
Definitely you can't have zero sized arrays by standard, but actually every most popular compiler gives you to do that. So I will try to explain why it can be bad
#include <cstdio>
int main() {
struct A {
A() {
printf("A()\n");
}
~A() {
printf("~A()\n");
}
int empty[0];
};
A vals[3];
}
I am like a human would expect such output:
A()
A()
A()
~A()
~A()
~A()
Clang prints this:
A()
~A()
GCC prints this:
A()
A()
A()
It is totally strange, so it is a good reason not to use empty arrays in C++ if you can.
Also there is extension in GNU C, which gives you to create zero length array in C, but as I understand it right, there should be at least one member in structure prior, or you will get very strange examples as above if you use C++.