On 07/08/2019 23:52, Bart wrote:
> On 07/08/2019 21:18, David Brown wrote:
>> On 07/08/2019 21:50, Christopher Collins wrote:
>>> On 2019-08-07, David Brown <
david...@hesbynett.no> wrote:
>>>> There is rarely any reason for wanting unaligned access, and no
>>>> justification for using it in code that should be portable.
>>>
>>> There is one good reason for wanting it: reduced code size.
>>
>> Nope.
>>
>> Write your code properly and safely (using shifts and masks, memcpy,
>> or compiler-specific features or intrinsics) and let the compiler turn
>> it into unaligned accesses. Writing safe, correct, and valid source
>> code is the programmer's responsibility. Turning it into small and
>> fast object code is the compiler's responsibility. Don't try to do
>> the compiler's job - work with it so that it can to the best job it can.
>
> You have to keep an eye on what's going on, otherwise you may end up
> with a struct that needs 65 bytes. Will the compiler say anything about
> that, or just accept it, and try and create arrays with a stride of 65
> bytes, or pad them to 128 bytes?
>
> I doubt it will re-design the struct to keep it to a power-of-two.
I don't see much connection between struct sizes and what we have
discussing, but I will try to answer anyway.
Compilers will add padding in structs to keep alignments correct for the
fields. The alignment for the struct itself will be that of the largest
alignment of any field, and there will be padding at the end of the
struct if needed to make the whole thing a multiple of this alignment
(so that arrays of the struct work).
So you won't get a struct array that has a stride of 65 bytes unless the
struct itself has size 65 bytes. And you won't get that unless the
component fields have alignments 1, 5 or 13. (I don't know any
platforms with types of alignment 5 or 13, but it is hypothetically
possible.)
As for checking the size of structs, compilers might be able to give you
help such as gcc's "-Wpadded" warning that is issued if there is any
padding added to structs. Most people don't want such a warning, of
course, but I have sometimes found it useful.
The best method of checking struct sizes IMHO is with C11 static assertions:
_Static_assert(sizeof(struct X) == 65, "Struct X should be 65 bytes");
or for C18, you might prefer just:
_Static_assert(sizeof(struct X) == 65)
Prior to C11, you can force compile-time errors with declarations like this:
#define STATIC_ASSERT(claim) \
typedef struct { char STATIC_ASSERT_(__LINE__) [ \
(claim) ? 1 : -1]; } STATIC_ASSERT___LINE__)
STATIC_ASSERT(sizeof(struct X) == 65);
Yes, the macro is a little ugly and the error message on failures
complains about array types of negative sizes, but it works nicely, can
be put at file scope or inside a function, and generates no extra code,
data space, or external symbols.
>
>> Compiler extensions like "packed" are fine in my book. Use them if
>> they make the code clearer and more efficient - assuming, of course,
>> that the lack of portability is not a problem. Compilers that don't
>> support such features will complain, so you don't get silent problems.
>
> (I've had silent problems with 'pack(1)', where int* accesses that I
> knew were aligned, were assumed to be unaligned by gcc, and generated
> byte-at-a-time accesses, which in that app slowed things down to 1/3 the
> expected speed. Another reason to keep a check on what it is doing.)
>
Don't use "packed" attributes or pragmas unless you have to. One
disadvantage is that you lose alignment information and, depending on
the compiler, flags and target, you might get inefficient code such as
the byte-at-a-time accesses you mentioned. But there are several ways
to avoid that in gcc:
1. Enable optimisation. That will coalesce the byte-at-a-time accesses
on targets that support unaligned accesses.
2. Add an attribute "aligned" to the type or variable to tell the
compiler about the struct's alignment. It will figure out the alignment
of the fields from there.
3. Use C11's _Alignas to get the same effect.
4. Wrap the packed struct in a union with a field that has the alignment
you want. Then use that outer union type rather than the struct type,
and the internal struct will have the biggest alignment of the union fields.
5. Use gcc's __builtin_assume_aligned() function when accessing members.
This would quickly make the code quite ugly, but it is the most
flexible as you can tell the compiler that a pointer is, for example, 3
bytes away from 8 byte alignment.