C global anonymous struct / union

前端 未结 6 1118
一个人的身影
一个人的身影 2021-01-26 14:53

I have a uint64 variable which often only requires high or low 32 bit access. I am using a 32-bit ARM Cortex M0, and to help with speed and I am trying to overlap the uint64 var

6条回答
  •  悲&欢浪女
    2021-01-26 15:08

    There is actually little to no reason to use a union. Instead, use shift/mask, possibly in inline functions to extract the two halves:

    static inline uint32_t upper(uint64_t val)
        { return (uint32_t)(val >> 32); }
    
    static inline uint32_t lower(uint64_t val)
        { return (uint32_t)val; }
    

    This will be very likely optimized by the compiler to the same code as the union-approach.

    However, as you are refering to anonymous struct/union members: Omitting the name is a feature of the struct/union which includes the member, not the member being a struct/union. So you can use:

    union {
        uint64_t v64;
        struct {
            uint32_t l32;
            uint32_t h32;
        };  // here the name can been omitted
    } my_flex_var;
    

    Problems are:

    • non-portable, possibly depends on ABI/PCS used (although the AAPCS is quite clear about this, there are others which might differ).
    • depends on little endian (some ARM CPUs/implementations allow for big-endian, too).
    • cannot be used on instances defined already as uint64_t.
    • less explicit than function loads.
    • might add overhead for compound types (non-register argument passing, placement on stack instead of registers, etc.

    Normal usage of a volatile is to load/store it always with full size. If that is not the case, a race condition might uccur and you are in the world of locking/mutex, etc. which makes things very much more complicated. If the two fields are only loosely related, you are very likely better off with two 32 bit variables or a struct thereof.

    Typical usage:

    volatile uint64_t v64;
    
    void int_handler(void)
    {
        uint64_t vt = v64;
    
        uint32_t l = lower(vt);
        uint32_t h = higher(vt);
    
    }
    

    This ensures the variable is read only once. With a proper compiler, the assignments to l, h will not generate any code, but the registers with vt are used. That depends, of course on your code, but even if there is some overhead, that will be negligible.

    (Sitenote: This is from my own practise as a long time embedded programmer)

提交回复
热议问题