Consider the following type:
struct S
{
char v;
};
Given an array of const S, is it possible to, in a standard conformant way, reinterpret it as an array of const char whose elements correspond to the value of the member v for each of the original array's elements, and vice-versa? For example:
const S a1[] = { {'a'}, {'4'}, {'2'}, {'\0'} };
const char* a2 = reinterpret_cast< const char* >(a1);
for (int i = 0; i < 4; ++i)
std::cout << std::boolalpha << (a1[i].v == a2[i]) << ' ';
Is the code above portable and would it print true true true true? If not, is there any other way of achieving this?
Obviously, it is possible to create a new array and initialize it with the member v of each element of the original array, but the whole idea is to avoid creating a new array.
Trivially, no - the struct may have padding. And that flat out breaks any reinterpretation as an array.
Formally the struct may have padding so that its size is greater than 1.
I.e., formally you can't reinterpret_cast and have fully portable code, except for ¹an array of only one item.
But for the in-practice, some years ago someone asked if there was now any compiler that by default would give sizeof(T) > 1 for struct T{ char x; };. I have yet to see any example. So in practice one can just static_assert that the size is 1, and not worry at all that this static_assert will fail on some system.
I.e.,
S const a1[] = { {'a'}, {'4'}, {'2'}, {'\0'} };
static_assert( sizeof( S ) == 1, "!" );
char const* const a2 = reinterpret_cast<char const*>( a1 );
for( int i = 0; i < 4; ++i )
{
assert( a1[i].v == a2[i] );
}
Since it's possible to interpret the C++14 and later standards in a way where the indexing has Undefined Behavior, based on a peculiar interpretation of "array" as referring to some original array, one might instead write this code in a more awkward and verbose but guaranteed valid way:
// I do not recommend this, but it's one way to avoid problems with some compiler that's
// based on an unreasonable, impractical interpretation of the C++14 standard.
#include <assert.h>
#include <new>
auto main() -> int
{
struct S
{
char v;
};
int const compiler_specific_overhead = 0; // Redefine per compiler.
// With value 0 for the overhead the internal workings here, what happens
// in the machine code, is the same as /without/ this verbose work-around
// for one impractical interpretation of the standard.
int const n = 4;
static_assert( sizeof( S ) == 1, "!" );
char storage[n + compiler_specific_overhead];
S* const a1 = ::new( storage ) S[n];
assert( (void*)a1 == storage + compiler_specific_overhead );
for( int i = 0; i < n; ++i ) { a1[i].v = "a42"[i]; } // Whatever
// Here a2 points to items of the original `char` array, hence no indexing
// UB even with impractical interpretation of the C++14 standard.
// Note that the indexing-UB-free code from this point, is exactly the same
// source code as the first code example that some claim has indexing UB.
char const* const a2 = reinterpret_cast<char const*>( a1 );
for( int i = 0; i < n; ++i )
{
assert( a1[i].v == a2[i] );
}
}
Notes:
¹ The standard guarantees that there's no padding at the start of the struct.
The pointer arithmetic in a2[i] is undefined, see C++14 5.7 [expr.add] p7:
For addition or subtraction, if the expressions P or Q have type "pointer to cv T", where T and the array element type are not similar (4.5), the behavior is undefined. [ Note: In particular, a pointer to a base class cannot be used for pointer arithmetic when the array contains objects of a derived class type. — end note ]
Because of this rule, even if there is no padding and the sizes match, type-based alias analysis allows the compiler to assume that a1[i] and a2[i] do not overlap (because the pointer arithmetic is only valid if a2 really is an array of char not just something with the same size and alignment, and if it's really an array of char it must be a separate object from an array of S).
I think I'd be inclined to use a compile-time transformation if the source data is constant:
#include <iostream>
#include <array>
struct S
{
char v;
};
namespace detail {
template<std::size_t...Is>
constexpr auto to_cstring(const S* p, std::index_sequence<Is...>)
{
return std::array<char, sizeof...(Is)> {
p[Is].v...
};
}
}
template<std::size_t N>
constexpr auto to_cstring(const S (&arr)[N])
{
return detail::to_cstring(arr, std::make_index_sequence<N>());
}
int main()
{
const /*expr if you wish*/ S a1[] = { {'a'}, {'4'}, {'2'}, {'\0'} };
const /*expr if you wish*/ auto a2 = to_cstring(a1);
for (int i = 0; i < 4; ++i)
std::cout << std::boolalpha << (a1[i].v == a2[i]) << ' ';
}
output:
true true true true
even when the data is not a constexpr, gcc and clang are pretty good at constant folding complex sequences like this.
Related
I am trying to turn a function, createArray, into a constexpr function.
This function creates an array from a contiguous section in memory marked by two arbitrarily named variables _start_array and _stop_array. I am able to iterate between the two and when the program is ran it prints
foo
bar
baz
This is the code so far:
#include <iostream>
#include <string>
#include <array>
struct element {
std::string_view value;
};
__attribute__( (used, section("array$a" )) ) unsigned int _start_array = 0xdeadbeef;
__attribute__( (used, section("array$b" )) ) element _element1_array = { .value = "foo" };
__attribute__( (used, section("array$b" )) ) element _element2_array = { .value = "bar" };
__attribute__( (used, section("array$b" )) ) element _element3_array = { .value = "baz" };
__attribute__( (used, section("array$c" )) ) unsigned int _stop_array = 0xdeadc0de;
std::array< element, 3 > createArray () { // TODO: constexpr
std::array< element, 3 > array;
int i = 0;
for ( element* it = reinterpret_cast< element* >( &_start_array + sizeof( int ) ); it < reinterpret_cast<element*>(&_stop_array); it++ ) {
array[ i++ ] = *it;
}
return array;
}
int main ( int argc, char* argv[] ) {
for ( auto i : createArray() ) {
std::cout << i.value << std::endl;
}
}
I am using MinGW on Windows.
During constant expression evaluation, the C++ object model is treated as reality, not a fiction created by a piece of paper. This means that anything which would be undefined behavior at runtime becomes ill-formed during constant evaluation.
As such, pointers in constant evaluation are not merely numbers. They are pointers to a specific object with full and complete knowledge of what that means. So converting a pointer value to an integer makes no sense.
And even if it did, what are you going to do with it? The address has no relation to the address of any other object. The address cannot be manipulated and then converted to a pointer to some other object, because that's not how things work at compile-time. Again, the object model is taken seriously at compile-time. If you get a pointer from something, the system needs to be able to verify that the "something" points to a real object of that type (or a type appropriate to the pointer type). This requires a compile-time pointer to be more than just an address.
Put simply, you cannot "treat the memory between _start and _stop as an array" at compile-time, because it isn't an array. You cannot just pretend things are a certain way at compile-time. To be fair, you can't do that at runtime either with well-defined behavior; it's just that the compiler won't stop you.
No, there is no standard way to reinterpret pointers in constexpr contexts.
Furthermore, accessing objects through reinterpreted pointers is well defined only in a few specific cases. Arbitrary T* isn't necessarily such case.
Iterate over a section in memory between two variables
There's no standard way to do this in general. There's generally not even a guarantee that such memory is allocated for the process.
If the variables in question are members of a standard layout class, then this may be achievable, but I can't think of a constexpr way.
I've been trying to figure out if this is an optimisation bug as it only seems to affect stack variables, and I wonder if there's some incorrect assumptions being made. I have this type which converts to and from a relative offset, and it has been working fine while using reinterpret_cast, but now I'm moving to static_cast, it's starting to cause issues in optimised builds. I need to get away from reinterpret_cast for safety certification reasons, so I don't have the option of keeping it as it is.
#include <iostream>
template <typename T>
class Ptr
{
public:
Ptr(const T* ptr = nullptr) : m_offset(GetOffset(ptr)) {}
T& operator*() const noexcept { return *GetPtr(); }
T* get() const noexcept { return GetPtr(); }
bool operator==(const T *ptr) const {
// comment this back in and it stops failing
//std::cout << "{op==" << get() << " == " << ptr << "}";
return get() == ptr;
}
private:
std::ptrdiff_t m_offset = 0;
inline T* GetPtr() const
{
auto offset = m_offset;
auto const_void_address = static_cast<const void*>(&m_offset);
auto const_char_address = static_cast<const char*>(const_void_address);
auto offset_address = const_cast<char*>(const_char_address);
auto final_address = static_cast<void*>(offset_address - offset);
return static_cast<T*>(final_address);
}
std::ptrdiff_t GetOffset(const void* ptr) const
{
auto void_address = static_cast<const void*>(&m_offset);
auto offset_address = static_cast<const char*>(void_address);
auto ptr_address = static_cast<const char*>(ptr);
return offset_address - ptr_address;
}
};
std::ostream& operator<<(std::ostream &stream, const Ptr<int> &rp) {
stream << rp.get();
return stream;
}
int main() {
int data = 123;
Ptr<int> rp(&data);
std::cout << "data " << data << " # " << &data << std::endl;
std::cout << "rp " << *rp << " get " << rp.get() << std::endl;
std::cout << (rp == &data) << std::endl;
std::cout << "(rp.get() == &data) = " << (rp.get() == &data) << std::endl;
std::cout << "(rp == &data) = " << (rp == &data) << std::endl;
return 0;
}
with optimisations turned on, I get output like this:
data 123 # 0x7ffe79544a34
rp 123 get 0x7ffe79544a34
0
(rp.get() == &data) = 0
(rp == &data) = 0
Which includes some output which is clearly inconsistent with itself.
I've tested this on GCC 8,9, and 11.2.
As soon as I drop back to -O0, it's fine.
If I uncomment the std::cout inside the operator==, it's fine.
If I go back to reinterpret_cast (return reinterpret_cast<T*>(reinterpret_cast<std::ptrdiff_t>(&m_offset) - offset);) it's fine.
If I allocate data as a pointer and initialise rp from that, it's fine too.
It seems to behave as I expect under clang (8 through 13 seem fine)
This feels like I am either not understanding where the UB is coming from, or there's a compiler optimisation bug here.
EDIT / UPDATE:
After looking at this is more detail I think the only solution is to do type punning in a semi-safe way, so I have tried this solution and it appears to work. (it appears, what I am now doing is part of C++20 and called bit_cast, so maybe this is valid?)
inline T* GetPtr() const
{
auto offset = m_offset;
intptr_t realAddress;
auto address_of_m_offset = &m_offset;
std::memcpy(&realAddress, &address_of_m_offset, sizeof( realAddress));
realAddress -= m_offset;
T *outValue;
std::memcpy(&outValue, &realAddress, sizeof( outValue));
return outValue;
}
std::ptrdiff_t GetOffset(const void* ptr) const
{
auto address_of_m_offset = &m_offset;
intptr_t myAddress;
std::memcpy(&myAddress, &address_of_m_offset, sizeof(myAddress));
intptr_t realAddress;
std::memcpy(&realAddress, &ptr, sizeof(realAddress));
return static_cast<ptrdiff_t>(myAddress - realAddress);
}
This no longer seems to cause a problem with GCC. I hear that std::memcpy is meant to be used for objects of same type where otherwise we would have used reinterpret_cast, so this makes sense to me.
Your undefined behaviour is in GetOffset.
This is how pointer subtraction is defined by the standard:
When two pointer expressions P and Q are subtracted, the type of the result is an implementation-defined signed integral type; this type shall be the same type that is defined as std::ptrdiff in the <cstddef> header ([support.types.layout])
If P and Q both evaluate to null pointer values, the result is 0.
Otherwise, if P and Q both point to, respectively, array elements i and j of the same array object x, the expression P - Q has the value i - j.
Otherwise, the behavior is undefined.
And here, P (which has the address of m_object) and Q (which has the address of data) aren't elements of the same array, so this is undefined behaviour.
Addition and subtraction of pointers and integers is also defined in terms of array elements:
When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.
If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
Otherwise, if P points to an array element i of an array object x with n elements ([dcl.array]), the expression P + J and J + P (Where J has value j point to the (possibly-hypothetical) array element i+j of x if 0≤i+j≤n and the expression P - J points to the (possibly-hypothetical) array element i-j of x if 0≤i-j≤n.
Otherwise, the behavior is undefined.
The pointer subtraction happens at offset_address - offset, where P is the address of m_offset and offset is probably some positive number. m_offset is the first element of the array, so i-j < 0
So, the compiler can see that GetPtr returns a pointer relative to the m_offset (in the char[sizeof(Ptr<int>)] array that aliases the object), so it cannot equal the address of data (without UB), and thus an optimizer can replace (rp.get() == &data) with false.
When you use ptrdiff_t, no such restriction on addition or subtraction exists. And though the standard doesn't guarantee that reinterpret_cast<char*>(reinterpret_cast<intptr_t>(char_pointer) + n) == char_pointer + n (pointers mapping linearly as you would expect) this is what happens when compiling with gcc on common architectures.
I need a safe way to alias between arbitrary POD types, conforming to ISO-C++11 explicitly considering 3.10/10 and 3.11 of n3242 or later.
There are a lot of questions about strict aliasing here, most of them regarding C and not C++. I found a "solution" for C which uses unions, probably using this section
union type that includes one of the aforementioned types among its
elements or nonstatic data members
From that I built this.
#include <iostream>
template <typename T, typename U>
T& access_as(U* p)
{
union dummy_union
{
U dummy;
T destination;
};
dummy_union* u = (dummy_union*)p;
return u->destination;
}
struct test
{
short s;
int i;
};
int main()
{
int buf[2];
static_assert(sizeof(buf) >= sizeof(double), "");
static_assert(sizeof(buf) >= sizeof(test), "");
access_as<double>(buf) = 42.1337;
std::cout << access_as<double>(buf) << '\n';
access_as<test>(buf).s = 42;
access_as<test>(buf).i = 1234;
std::cout << access_as<test>(buf).s << '\n';
std::cout << access_as<test>(buf).i << '\n';
}
My question is, just to be sure, is this program legal according to the standard?*
It doesn't give any warnings whatsoever and works fine when compiling with MinGW/GCC 4.6.2 using:
g++ -std=c++0x -Wall -Wextra -O3 -fstrict-aliasing -o alias.exe alias.cpp
* Edit: And if not, how could one modify this to be legal?
This will never be legal, no matter what kind of contortions you perform with weird casts and unions and whatnot.
The fundamental fact is this: two objects of different type may never alias in memory, with a few special exceptions (see further down).
Example
Consider the following code:
void sum(double& out, float* in, int count) {
for(int i = 0; i < count; ++i) {
out += *in++;
}
}
Let's break that out into local register variables to model actual execution more closely:
void sum(double& out, float* in, int count) {
for(int i = 0; i < count; ++i) {
register double out_val = out; // (1)
register double in_val = *in; // (2)
register double tmp = out_val + in_val;
out = tmp; // (3)
in++;
}
}
Suppose that (1), (2) and (3) represent a memory read, read and write, respectively, which can be very expensive operations in such a tight inner loop. A reasonable optimization for this loop would be the following:
void sum(double& out, float* in, int count) {
register double tmp = out; // (1)
for(int i = 0; i < count; ++i) {
register double in_val = *in; // (2)
tmp = tmp + in_val;
in++;
}
out = tmp; // (3)
}
This optimization reduces the number of memory reads needed by half and the number of memory writes to 1. This can have a huge impact on the performance of the code and is a very important optimization for all optimizing C and C++ compilers.
Now, suppose that we don't have strict aliasing. Suppose that a write to an object of any type can affect any other object. Suppose that writing to a double can affect the value of a float somewhere. This makes the above optimization suspect, because it's possible the programmer has in fact intended for out and in to alias so that the sum function's result is more complicated and is affected by the process. Sounds stupid? Even so, the compiler cannot distinguish between "stupid" and "smart" code. The compiler can only distinguish between well-formed and ill-formed code. If we allow free aliasing, then the compiler must be conservative in its optimizations and must perform the extra store (3) in each iteration of the loop.
Hopefully you can see now why no such union or cast trick can possibly be legal. You cannot circumvent fundamental concepts like this by sleight of hand.
Exceptions to strict aliasing
The C and C++ standards make special provision for aliasing any type with char, and with any "related type" which among others includes derived and base types, and members, because being able to use the address of a class member independently is so important. You can find an exhaustive list of these provisions in this answer.
Furthermore, GCC makes special provision for reading from a different member of a union than what was last written to. Note that this kind of conversion-through-union does not in fact allow you to violate aliasing. Only one member of a union is allowed to be active at any one time, so for example, even with GCC the following would be undefined behavior:
union {
double d;
float f[2];
};
f[0] = 3.0f;
f[1] = 5.0f;
sum(d, f, 2); // UB: attempt to treat two members of
// a union as simultaneously active
Workarounds
The only standard way to reinterpret the bits of one object as the bits of an object of some other type is to use an equivalent of memcpy. This makes use of the special provision for aliasing with char objects, in effect allowing you to read and modify the underlying object representation at the byte level. For example, the following is legal, and does not violate strict aliasing rules:
int a[2];
double d;
static_assert(sizeof(a) == sizeof(d));
memcpy(a, &d, sizeof(d));
This is semantically equivalent to the following code:
int a[2];
double d;
static_assert(sizeof(a) == sizeof(d));
for(size_t i = 0; i < sizeof(a); ++i)
((char*)a)[i] = ((char*)&d)[i];
GCC makes a provision for reading from an inactive union member, implicitly making it active. From the GCC documentation:
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. See Structures unions enumerations and bit-fields implementation. However, this code might not:
int f() {
union a_union t;
int* ip;
t.d = 3.0;
ip = &t.i;
return *ip;
}
Similarly, access by taking the address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.:
int f() {
double d = 3.0;
return ((union a_union *) &d)->i;
}
Placement new
(Note: I'm going by memory here as I don't have access to the standard right now).
Once you placement-new an object into a storage buffer, the lifetime of the underlying storage objects ends implicitly. This is similar to what happens when you write to a member of a union:
union {
int i;
float f;
} u;
// No member of u is active. Neither i nor f refer to an lvalue of any type.
u.i = 5;
// The member u.i is now active, and there exists an lvalue (object)
// of type int with the value 5. No float object exists.
u.f = 5.0f;
// The member u.i is no longer active,
// as its lifetime has ended with the assignment.
// The member u.f is now active, and there exists an lvalue (object)
// of type float with the value 5.0f. No int object exists.
Now, let's look at something similar with placement-new:
#define MAX_(x, y) ((x) > (y) ? (x) : (y))
// new returns suitably aligned memory
char* buffer = new char[MAX_(sizeof(int), sizeof(float))];
// Currently, only char objects exist in the buffer.
new (buffer) int(5);
// An object of type int has been constructed in the memory pointed to by buffer,
// implicitly ending the lifetime of the underlying storage objects.
new (buffer) float(5.0f);
// An object of type int has been constructed in the memory pointed to by buffer,
// implicitly ending the lifetime of the int object that previously occupied the same memory.
This kind of implicit end-of-lifetime can only occur for types with trivial constructors and destructors, for obvious reasons.
Aside from the error when sizeof(T) > sizeof(U), the problem there could be, that the union has an appropriate and possibly higher alignment than U, because of T.
If you don't instantiate this union, so that its memory block is aligned (and large enough!) and then fetch the member with destination type T, it will break silently in the worst case.
For example, an alignment error occurs, if you do the C-style cast of U*, where U requires 4 bytes alignment, to dummy_union*, where dummy_union requires alignment to 8 bytes, because alignof(T) == 8. After that, you possibly read the union member with type T aligned at 4 instead of 8 bytes.
Alias cast (alignment & size safe reinterpret_cast for PODs only):
This proposal does explicitly violate strict aliasing, but with static assertions:
///#brief Compile time checked reinterpret_cast where destAlign <= srcAlign && destSize <= srcSize
template<typename _TargetPtrType, typename _ArgType>
inline _TargetPtrType alias_cast(_ArgType* const ptr)
{
//assert argument alignment at runtime in debug builds
assert(uintptr_t(ptr) % alignof(_ArgType) == 0);
typedef typename std::tr1::remove_pointer<_TargetPtrType>::type target_type;
static_assert(std::tr1::is_pointer<_TargetPtrType>::value && std::tr1::is_pod<target_type>::value, "Target type must be a pointer to POD");
static_assert(std::tr1::is_pod<_ArgType>::value, "Argument must point to POD");
static_assert(std::tr1::is_const<_ArgType>::value ? std::tr1::is_const<target_type>::value : true, "const argument must be cast to const target type");
static_assert(alignof(_ArgType) % alignof(target_type) == 0, "Target alignment must be <= source alignment");
static_assert(sizeof(_ArgType) >= sizeof(target_type), "Target size must be <= source size");
//reinterpret cast doesn't remove a const qualifier either
return reinterpret_cast<_TargetPtrType>(ptr);
}
Usage with pointer type argument ( like standard cast operators such as reinterpret_cast ):
int* x = alias_cast<int*>(any_ptr);
Another approach (circumvents alignment and aliasing issues using a temporary union):
template<typename ReturnType, typename ArgType>
inline ReturnType alias_value(const ArgType& x)
{
//test argument alignment at runtime in debug builds
assert(uintptr_t(&x) % alignof(ArgType) == 0);
static_assert(!std::tr1::is_pointer<ReturnType>::value ? !std::tr1::is_const<ReturnType>::value : true, "Target type can't be a const value type");
static_assert(std::tr1::is_pod<ReturnType>::value, "Target type must be POD");
static_assert(std::tr1::is_pod<ArgType>::value, "Argument must be of POD type");
//assure, that we don't read garbage
static_assert(sizeof(ReturnType) <= sizeof(ArgType),"Target size must be <= argument size");
union dummy_union
{
ArgType x;
ReturnType r;
};
dummy_union dummy;
dummy.x = x;
return dummy.r;
}
Usage:
struct characters
{
char c[5];
};
//.....
characters chars;
chars.c[0] = 'a';
chars.c[1] = 'b';
chars.c[2] = 'c';
chars.c[3] = 'd';
chars.c[4] = '\0';
int r = alias_value<int>(chars);
The disadvantage of this is, that the union may require more memory than actually needed for the ReturnType
Wrapped memcpy (circumvents alignment and aliasing issues using memcpy):
template<typename ReturnType, typename ArgType>
inline ReturnType alias_value(const ArgType& x)
{
//assert argument alignment at runtime in debug builds
assert(uintptr_t(&x) % alignof(ArgType) == 0);
static_assert(!std::tr1::is_pointer<ReturnType>::value ? !std::tr1::is_const<ReturnType>::value : true, "Target type can't be a const value type");
static_assert(std::tr1::is_pod<ReturnType>::value, "Target type must be POD");
static_assert(std::tr1::is_pod<ArgType>::value, "Argument must be of POD type");
//assure, that we don't read garbage
static_assert(sizeof(ReturnType) <= sizeof(ArgType),"Target size must be <= argument size");
ReturnType r;
memcpy(&r,&x,sizeof(ReturnType));
return r;
}
For dynamic sized arrays of any POD type:
template<typename ReturnType, typename ElementType>
ReturnType alias_value(const ElementType* const array,const size_t size)
{
//assert argument alignment at runtime in debug builds
assert(uintptr_t(array) % alignof(ElementType) == 0);
static const size_t min_element_count = (sizeof(ReturnType) / sizeof(ElementType)) + (sizeof(ReturnType) % sizeof(ElementType) != 0 ? 1 : 0);
static_assert(!std::tr1::is_pointer<ReturnType>::value ? !std::tr1::is_const<ReturnType>::value : true, "Target type can't be a const value type");
static_assert(std::tr1::is_pod<ReturnType>::value, "Target type must be POD");
static_assert(std::tr1::is_pod<ElementType>::value, "Array elements must be of POD type");
//check for minimum element count in array
if(size < min_element_count)
throw std::invalid_argument("insufficient array size");
ReturnType r;
memcpy(&r,array,sizeof(ReturnType));
return r;
}
More efficient approaches may do explicit unaligned reads with intrinsics, like the ones from SSE, to extract primitives.
Examples:
struct sample_struct
{
char c[4];
int _aligner;
};
int test(void)
{
const sample_struct constPOD = {};
sample_struct pod = {};
const char* str = "abcd";
const int* constIntPtr = alias_cast<const int*>(&constPOD);
void* voidPtr = alias_value<void*>(pod);
int intValue = alias_value<int>(str,strlen(str));
return 0;
}
EDITS:
Assertions to assure conversion of PODs only, may be improved.
Removed superfluous template helpers, now using tr1 traits only
Static assertions for clarification and prohibition of const value (non-pointer) return type
Runtime assertions for debug builds
Added const qualifiers to some function arguments
Another type punning function using memcpy
Refactoring
Small example
I think that at the most fundamental level, this is impossible and violates strict aliasing. The only thing you've achieved is tricking the compiler into not noticing.
My question is, just to be sure, is this program legal according to the standard?
No. The alignment may be unnatural using the alias you have provided. The union you wrote just moves the point of the alias. It may appear to work, but that program may fail when CPU options, ABI, or compiler settings change.
And if not, how could one modify this to be legal?
Create natural temporary variables and treat your storage as a memory blob (moving in and out of the blob to/from temporaries), or use a union which represents all your types (remember, one active element at a time here).
Why this is not allowed?
#include <cstdio>
struct Foo {
int fooId;
char arr[ ];
} fooList[] =
{ {1, {'a', 'b'}},
{2, {'c', 'd'}}
};
int main()
{
for (int i = 0; i < 2; i++)
printf("%d %c\n", fooList[i].fooId, fooList[i].arr[0]);
}
whereas, this is allowed:
struct Foo {
int fooId;
char arr[2]; // this line modified
} fooList[] =
{ {1, {'a', 'b'}},
{2, {'c', 'd'}}
};
Only the last member of a C struct can be flexible as in arr[].
Shamelessly copying from paragraph 6.7.2.1, sub-paragraph 16 of the ISO C99 standard:
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. With two exceptions,
the flexible array member is ignored.
First, the size of the structure shall
be equal to the offset of the last
element of an otherwise identical
structure that replaces the flexible
array member with an array of
unspecified length.106)...
EDIT:
As for C++, see this. Bottom-line: flexible array members are not allowed in C++ at all - at least for the time being.
In C++ all members of an user defined type must have complete types, and the member arr does not have a complete type unless you give it a size.
In C, the struct definition would compile, but you might not get what you want. The problem is that an array without size is allowed at the end of a struct to be used as a proxy to access the contiguous block of memory after the instance. This allows a dumb vector implementation as:
typedef struct vector {
int size;
char buffer[];
} vector;
vector* create_vector( int size ) {
vector* p = (vector*) malloc( sizeof *p + size ); // manually allocate "size" extra
p->size = size;
};
int main() {
vector* v = create_vector(10);
for ( int i = 0; i < v->size; ++i )
printf("%d\n", v->buffer[i] );
free(v);
}
But the language does not allow you to initialize with the curly braces as the compiler does not know how much memory has to be held (in general, in some circumstances it can know). The size-less member of the struct is only a way of accessing beyond the end of the object, it does not hold memory in itself:
printf( "sizeof(vector)=%d\n", sizeof(vector) ); // == sizeof(int)
In C++03, this is not allowed in struct or class!
Comeau C++ compiler gives this error:
"ComeauTest.c", line 3: error:
incomplete type is not allowed
char arr[ ];
^
Exactly simlar question yesterday : Difference between int* and int[] in C++
This question already has answers here:
How do I find the length of an array?
(30 answers)
Closed 2 years ago.
I have
int list[] = {1, 2, 3};
How to I get the size of list?
I know that for a char array, we can use strlen(array) to find the size, or check with '\0' at the end of the array.
I tried sizeof(array) / sizeof(array[0]) as some answers said, but it only works in main? For example:
int size(int arr1[]){
return sizeof(arr1) / sizeof(arr1[0]);
}
int main() {
int list[] = {1, 2, 3};
int size1 = sizeof(list) / sizeof(list[0]); // ok
int size2 = size(list_1); // no
// size1 and size2 are not the same
}
Why?
Try this:
sizeof(list) / sizeof(list[0]);
Because this question is tagged C++, it is always recommended to use std::vector in C++ rather than using conventional C-style arrays.
An array-type is implicitly converted into a pointer-type when you pass it to a function.
Have a look at this.
In order to correctly print the sizeof an array inside any function, pass the array by reference to that function (but you need to know the size of that array in advance).
You would do it like so for the general case
template<typename T,int N>
//template argument deduction
int size(T (&arr1)[N]) //Passing the array by reference
{
return sizeof(arr1)/sizeof(arr1[0]); //Correctly returns the size of 'list'
// or
return N; //Correctly returns the size too [cool trick ;-)]
}
The "standard" C way to do this is
sizeof(list) / sizeof(list[0])
You could use boost::size, which is basically defined this way:
template <typename T, std::size_t N>
std::size_t size(T const (&)[N])
{
return N;
}
Note that if you want to use the size as a constant expression, you'll either have to use the sizeof a / sizeof a[0] idiom or wait for the next version of the C++ standard.
You can't do that for a dynamically allocated array (or a pointer). For static arrays, you can use sizeof(array) to get the whole array size in bytes and divide it by the size of each element:
#define COUNTOF(x) (sizeof(x)/sizeof(*x))
To get the size of a dynamic array, you have to keep track of it manually and pass it around with it, or terminate it with a sentinel value (like '\0' in null terminated strings).
Update: I realized that your question is tagged C++ and not C. You should definitely consider using std::vector instead of arrays in C++ if you want to pass things around:
std::vector<int> v;
v.push_back(1);
v.push_back(2);
std::cout << v.size() << std::endl; // prints 2
Since you've marked this as C++, it's worth mentioning that there is a somewhat better way than the C-style macro:
template <class T, size_t N>
size_t countof(const T &array[N]) { return N; }
This has the advantage that if you accidentally try to pass something other than an array to it, the code simply won't compile (whereas passing a pointer to the C macro will compile but produce a bad result. The disadvantage is that this doesn't give you a compile-time constant, so you can't do something like this:
int a[20];
char x[countof(a)];
In C++11 or newer, you can add constexpr to get a compile-time constant:
template <class T, size_t N>
constexpr size_t countof(const T &array[N]) { return N; }
If you really want to support the same on older compilers, there is a way, originally invented by Ivan Johnson, AFAIK:
#define COUNTOF(x) ( \
0 * sizeof( reinterpret_cast<const ::Bad_arg_to_COUNTOF*>(x) ) + \
0 * sizeof( ::Bad_arg_to_COUNTOF::check_type((x), &(x)) ) + \
sizeof(x) / sizeof((x)[0]) )
class Bad_arg_to_COUNTOF
{
public:
class Is_pointer;
class Is_array {};
template<typename T>
static Is_pointer check_type(const T*, const T* const*);
static Is_array check_type(const void*, const void*);
};
This uses sizeof(x)/sizeof(x[0]) to compute the size, just like the C macro does, so it gives a compile-time constant. The difference is that it first uses some template magic to cause a compile error if what you've passed isn't the name of an array. It does that by overloading check_type to return an incomplete type for a pointer, but a complete type for an array. Then (the really tricky part) it doesn't actually call that function at all -- it just takes the size of the type the function would return, which is zero for the overload that returns the complete type, but not allowed (forcing a compile error) for the incomplete type.
IMO, that's a pretty cool example of template meta programming -- though in all honesty, the result is kind of pointless. You really only need that size as a compile time constant if you're using arrays, which you should normally avoid in any case. Using std::vector, it's fine to supply the size at run-time (and resize the vector when/if needed).
Besides Carl's answer, the "standard" C++ way is not to use a C int array, but rather something like a C++ STL std::vector<int> list which you can query for list.size().
when u pass any array to some function. u are just passing it's starting address, so for it to work u have to pass it size also for it to work properly. it's the same reason why we pass argc with argv[] in command line arguement.
You can make a template function, and pass the array by reference to achieve this.
Here is my code snippet
template <typename TypeOfData>
void PrintArray(TypeOfData &arrayOfType);
int main()
{
char charArray[] = "my name is";
int intArray[] = { 1,2,3,4,5,6 };
double doubleArray[] = { 1.1,2.2,3.3 };
PrintArray(charArray);
PrintArray(intArray);
PrintArray(doubleArray);
}
template <typename TypeOfData>
void PrintArray(TypeOfData &arrayOfType)
{
int elementsCount = sizeof(arrayOfType) / sizeof(arrayOfType[0]);
for (int i = 0; i < elementsCount; i++)
{
cout << "Value in elements at position " << i + 1 << " is " << arrayOfType[i] << endl;
}
}
You have to use sizeof() function.
Code Snippet:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int arr[] ={5, 3, 6, 7};
int size = sizeof(arr) / sizeof(arr[0]);
cout<<size<<endl;
return 0;
}
int arr1[] = {8, 15, 3, 7};
int n = sizeof(arr1)/sizeof(arr1[0]);
So basically sizeof(arr1) is giving the size of the object being pointed to, each element maybe occupying multiple bits so dividing by the number of bits per element (sizeof(arr1[0]) gives you the actual number of elements you're looking for, i.e. 4 in my example.
This method work when you are using a class: In this example you will receive a array, so the only method that worked for me was these one:
template <typename T, size_t n, size_t m>
Matrix& operator= (T (&a)[n][m])
{
int arows = n;
int acols = m;
p = new double*[arows];
for (register int r = 0; r < arows; r++)
{
p[r] = new double[acols];
for (register int c = 0; c < acols; c++)
{
p[r][c] = a[r][c]; //A[rows][columns]
}
}
https://www.geeksforgeeks.org/how-to-print-size-of-an-array-in-a-function-in-c/
Assuming you merely want to know the size of an array whose type you know (int) but whose size, obviously, you don't know, it is suitable to verify whether the array is empty, otherwise you will end up with a division by zero (causing a Float point exception).
int array_size(int array[]) {
if(sizeof(array) == 0) {
return 0;
}
return sizeof(array)/sizeof(array[0]);
}
If you want to know how much numbers the array have, you want to know the array length. The function sizeof(var) in C gives you the bytes in the computer memory. So if you know the memory the int occupy you can do like this:
int arraylength(int array[]) {
return sizeof(array) / sizeof(int); // Size of the Array divided by the int size
}