C++ Logo


Advanced search

Re: [std-proposals] [[packed]] std::unaligned

From: Sebastian Wittmeier <wittmeier_at_[hidden]>
Date: Wed, 20 Dec 2023 07:55:53 +0100
Hi Frederick, so you have an object, which is not meant for unaligned storage (the pointer within string has exists and has alignment requirements and is no union like type.   You copy/relocate it nevertheless.   For it you need full knowledge of the private working of the class.   Why do you want to store the data in attributes with a similar type than the aligned string?   Just create new members for archiving the unaligned version and copy the data structures. The unaligned version cannot be accessed anyway, until it is extracted again.   Seems to be overly fragile, working for one specific case and for that case too complicated and not performant. Apart from that the casts and address arithmetic is very hacky.   To go one step further: What if your objects points to other objects and they point back. Then testing, whether the pointer points into the object and with which offset won't work.   Going two steps forward: A pointer is only the simplest example of a non-trivial member. What if your micro-controller has a RTOS with a callback? What if there is DMA?     I think either  - the storing in unaligned memory is just a private expansion of a codebase; it can have support by member functions  - with attributes and the type system the implementation supports the object fully living at unaligned storage   But semi-automatic packing is just too involved and a too special case for any standardization IMHO.   -----Ursprüngliche Nachricht----- Von:Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]> Gesendet:Mi 20.12.2023 04:42 Betreff:Re: [std-proposals] [[packed]] std::unaligned An:std-proposals_at_[hidden]; CC:Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>; On Tue, Dec 19, 2023 at 5:07 PM Frederick Virchanza Gotham wrote: > > I mean when you do: > >     char c; >     char *p = &c; >     long double *p2 = static_cast<long double*>(static_cast<void*>(p)); > > and then convert it back: > >     char *p3 = static_cast<char*>(static_cast<void*>(p2)); > > then you might not get back the original memory address. Let's say we have an object of:        std::basic_string<long double> So the pointer that resides inside the object will be a 'long double*' instead of a 'char*'. I'm trying to figure out how to relocate such an object to unaligned space without having a 'long double*' with an invalid value (i.e. pointing to an unaligned address). So to use a more simple example than 'basic_string', let's use the following class:    struct Monkey {        long double *p;        long double buf[8u];        Monkey(void) : p(buf) {}    }; When we relocate an object of this class, we must check if 'p' points to within the object, and if it does then we must adjust it. First I wrote a function to get the modulus of the alignment:    template<typename T>    inline std::ptrdiff_t alignment_modulus(void const *const arg)    {        assert( nullptr != arg );    #ifdef UINTPTR_MAX        return reinterpret_cast<std::uintptr_t>(arg) % alignof(T);    #else        // This implementation does not need std::uintptr_t (which might not exist)        using std::byte;        std::ptrdiff_t retval = alignof(T);        byte *p = static_cast<byte*>(const_cast<void*>(arg));        std::size_t buffer_size = sizeof(T);        for ( ; ; ++p, --retval )        {            void *pv = p;            if ( nullptr != std::align(alignof(T), sizeof(T), pv, buffer_size) )            {                return retval % alignof(T);            }        }    #endif    } Next, I think the '_Relocate' function would be something like:    void _Relocate(void *const dst, void *const src)    {        using T = Monkey;        using std::byte;        std::memcpy(dst,src,__datasizeof(T));        long double  *pld;        std::memcpy(&pld,src,sizeof pld);  // 'pld' will always be valid (because of Line #71)        byte *p = static_cast<byte*>(static_cast<void*>(pld));        p += alignment_modulus<T>(src);        if ( p  <  static_cast<byte*>(src) ) return;        if ( p >= (static_cast<byte*>(src) + __datasizeof(T))) return;        // If control reaches here, we must adjust the pointer        // but we must be careful because 'long double*' might        // have less precision than 'byte*'. We will do this        // in three steps.        // Step 1: Add the offset to 'p'        p += static_cast<byte*>(dst) - static_cast<byte*>(src);        // Step 2: Subtract the alignment modulus        p -= alignment_modulus<T>(p);        // Step 3: Convert to 'long double*' and store in (possibly unaligned) destination        assert( 0u == alignment_modulus<long double>(p) );        pld = static_cast<long double*>(static_cast<void*>(p));        std::memcpy(dst,&pld,sizeof pld);    } Putting it all together would be something like:        https://godbolt.org/z/59e6x7W8r -- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2023-12-20 06:55:55