How to determine maximum required alignment in C99
Asked Answered
I

2

8

Is there a portable way that only relies on what the C99 standard provides to find out the maximum required alignment that is needed for any data type.

Like maxalign_t in C++11.

What I'm currently doing is calculating the least common multiple (lcm) of the alignments of int, long int, long long int, double, void * and size_t as best effort way of determining the alignment.

Update: I currently need this for implementing a wrapper around malloc that stores metadata at the beginning of the block of memory and returns a pointer with a higher address than what malloc has returned.

Inept answered 8/7, 2016 at 16:4 Comment(0)
R
3

There isn't really a good way to do that, which is why maxalign_t was introduced by C11. Though, I cannot imagine an ordinary system where a type with higher alignment requirements than intmax_t exists so you might as well use that and get the right answer for 99% of the systems when maxalign_t is not available.

Rimini answered 8/7, 2016 at 16:29 Comment(11)
Sad to hear that. I'll evaluate if it is possible to switch to C11 otherwise use intmax_t.Inept
To be even more paranoid you could use the alignment requirement of intmax_t or long double, whichever is greater.Adelaidaadelaide
@SteveSummit: Don't forget void*. A 128-bit pointer type could combine information about base address, size, and offset, allowing erroneous pointer manipulations to be trapped much more effectively than would be possible using simple linear pointers.Flyspeck
@Inept Updating my previous comment: To be really paranoid you could use the maximum alignment requirement of intmax_t, long double, void *, and void (*)() (that is, of the largest integral, largest floating-point, generic data pointer, and function pointer types).Adelaidaadelaide
@SteveSummit: Would that really take care of things? I don't think anything would forbid a compiler from requiring that, for at least some types, a T[N] would have a coarser alignment requirement than a T for even values of N (such an alignment requirement would not affect the size or stride of any array, except that certain structs containing an array would be bigger. I think it would be very useful to have a testable standard macro via which a compiler could assert that arrays have the same alignment as the underlying element, but at present there's no means via which programs...Flyspeck
...can indicate that they rely upon such behaviors.Flyspeck
@Flyspeck It's very likely that it does. I doubt there is a better way, especially one that is portable.Rimini
What about __m128 and all their lot?Meghan
@Meghan 128 bit ints are confusing me too. Can't align to long double or any of the above suggestions because those have 8 byte requirements where a 128 bit int would have a 16 byte one.Skeens
@SteveSummit Does that mean finding the maximum value from the values returned by sizeof for each of them, or the LCM as OP is doing?Aldoaldol
@Aldoaldol As alignment requirements are powers of 2, this comes out to the same.Rimini
W
1

You can determine the maximum supported alignment empirically by allocating several chunks and seeing if each chunk is aligned on a 16, 8, or 4 byte boundary.

bool GetConsistentAlignment( std::size_t alignment )
{
    const unsigned int chunkCount = 16;
    void * places[ chunkCount ];
    memset( places, 0, sizeof(places) );
    bool consistent = true;

    for ( unsigned int ii = 0;  ii < chunkCount; ++ii )
    {
        const std::size_t size = 1024 + rand() % 4096;
        void * chunk = malloc( size );
        places[ ii ] = chunk;
    }

    for ( unsigned int ii = 0;  ii < chunkCount; ++ii )
    {
        void * chunk = places[ ii ];
        const std::size_t place = reinterpret_cast< const std::size_t >( chunk );
        if ( place % alignment != 0 )
        {
            consistent = false;
        }
        free( chunk );
    }

    return consistent;
}

std::size_t GetMaxSupportedAlignment()
{
    static std::size_t maxAlignment = 0;

    if ( maxAlignment == 0 )
    {
        std::srand( std::time( 0 ) );
        std::size_t alignment = 64;
        while ( alignment > 1 )
        {
            const bool isConsistentAlignment = GetConsistentAlignment( alignment );
            if ( isConsistentAlignment )
            {
                break;
            }
            alignment /= 2;
        }
        maxAlignment = alignment;
    }

    return maxAlignment;
}

Calling GetMaxSupportedAlignment() will return 8 on 64-bit operating systems and 4 on many 32-bit systems.

Winchell answered 20/9, 2017 at 4:22 Comment(1)
This is not really a practical solution, more like an esoteric one. Your approach is probabilistic, it is not guaranteed to always produce the same result. Also it relies on heap allocations (not too nice) and it is actually C++, not C99.Inept

© 2022 - 2024 — McMap. All rights reserved.