11

sizeof (struct Astruct)如果不均匀,是否有任何可能的方法使编译器退出?

背景信息:我们有一个 16 位微处理器,如果 16 位值未对齐,它将给出处理器对齐错误。这可能发生在以下场景中:

typedef struct
{
    U8BIT u8BitValue1;
    U8BIT u8BitValue2;
    U8BIT u8BitValue3;
} unevenAmountOf8BitValues;

typedef struct
{
    U16BIT u16BitValue1;
    U16BIT u16BitValue2;
} my16BitValues;

#define U8BIT_COUNT 3
#define U16BIT_COUNT 2

typedef struct
{
    unevenAmountOf8BitValues u8BitValues;
    my16BitValues u16BitValues;
} valuesCombined;

typedef union
{
    valuesCombined myValues;
    U8BIT buffer[sizeof(valuesCombined)];

    struct
    {
         U8BIT bufferU8[U8BIT_COUNT];
         U16BIT bufferU16[U16BIT_COUNT]; /* <<-- missalignment */
    } valuesPerType;
} myValuesInRamAndRom

我们现在要做的是手动计算 U8BIT/U16BIT/U32BIT 值的数量(嗯,使用 excel 跟踪数量)并将其放入U(8/16/32)BIT_COUNT定义中,然后如下:

#if U8BIT_COUNT % 2 == 1
#error The number of U8BIT parameters need to be even, add a dummy
#endif

跟踪 U8-/U16-/U32BIT 值的数量很容易出错,而且我们有很多时候在想“嘿,它不工作”,一个小时或之后,哦!该死,忘记调整定义的值的数量。

一种首选方法是使用 sizeof 运算符,但它不能用于错误检查,我真的很想保留它。

那么无论如何使用 sizeof 运算符保​​持某种形式的错误检查 U8BIT 值的数量必须是偶数吗?


LundinAaron McDaid的联合解决方案:

#define COMPILE_TIME_ASSERT(expr) {typedef U8BIT COMP_TIME_ASSERT[((!!(expr))*2-1)];}
4

3 回答 3

10

使用 C11 编译器,使用:

static_assert (sizeof(the struct) % 2 == 0,
               "Misaligned");

使用较旧的编译器,您可以使用肮脏的技巧,例如

#define COMPILE_TIME_ASSERT(expr) {typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0];}

...

COMPILE_TIME_ASSERT(sizeof(the_struct) % 2 == 0);

但是,针对您的特定问题的真正解决方案可能是确保启用 struct padding。那么你不应该得到任何错位。

于 2013-10-16T12:39:41.890 回答
9

这是可能的,使用Linux 内核中也使用的技巧:

#define BUILD_BUG_OR_ZERO(e) (sizeof(struct{ int:-!!(e);}))
#define ENSURE_EVEN_SIZE(e) BUILD_BUG_OR_ZERO(sizeof(e) % 2 == 1)

struct uneven{
  char a,b,c;
};

struct even{
  char a,b,c,d;
};

int main(){
  ENSURE_EVEN_SIZE(struct even);
  /* compiler error: */
  ENSURE_EVEN_SIZE(struct uneven);
}

如果sizeof(e) % 2 == 1为真,则位域int:-!!(e)将具有负大小,这是禁止的。(爱迪生

于 2013-10-16T12:34:20.927 回答
5

这是允许在同一个文件中多次使用同一个断言宏的版本。

/*
    General purpose static assert.

    Works in/out -side of scope:
        STATIC_ASSERT(sizeof(long)==8);
        int main()
        {
            STATIC_ASSERT(sizeof(int)==4);
        }
*/
#define STATIC_ASSERT(X)            STATIC_ASSERT2(X,__LINE__)

/*
    These macros are required by STATIC_ASSERT to make token pasting work.
    Not really useful by themselves.
*/
#define STATIC_ASSERT2(X,L)         STATIC_ASSERT3(X,L)
#define STATIC_ASSERT3(X,L)         STATIC_ASSERT_MSG(X,at_line_##L)

/*
    Static assertion with special error message.
    Note: It depends on compiler whether message is visible or not!

    STATIC_ASSERT_MSG(sizeof(long)==8, long_is_not_eight_bytes);
*/
#define STATIC_ASSERT_MSG(COND,MSG) \
    typedef char static_assertion_##MSG[(!!(COND))*2-1]
于 2013-10-16T13:33:37.643 回答