如果一个结构体定义了uint16_t单词和uint8_t字节,那么数组的大小会增加一倍。

6

我有一个数组,每个元素可以是uint16_t类型或者是一对uint8_t类型。

它的元素被定义为uint16_t和2个uint8_t的子数组的联合体。

不幸的是,编译器(MicroChip XC16)为这个数组分配了两倍于应该分配的内存。

typedef union {
   uint16_t u16;   // As uint16_t
   uint8_t  u8[2]; // As uint8_t
} my_array_t;

my_array_t my_array[1]; // 1 word array, for testing

my_array[0].u8[0] = 1;
my_array[0].u8[1] = 2;
uint8_t byte_0 = my_array[0].u8[0]; // Gets 0x01
uint8_t byte_1 = my_array[0].u8[1]; // Gets 0x02
uint16_t byte_0 = my_array[0].u16; // Gets 0x0201

编译器分配了4个字节,而不是应该的2个字节。
解决方法:如果我将结构体更改为:
typedef union {
   uint16_t u16;   // As uint16_t
   uint8_t  u8[1];   // As uint8_t
} my_array_t;

编译器按照应有的方式分配了2个字节,但这是错误的。
my_array[0].u8[1] = 2;

虽然它仍能正常工作:
uint8_t byte_1 = my_array[0].u8[1]; // Gets 0x02

除了调试器不显示其值的不便之外。

问题:我应该使用解决方法,还是使用更好的解决方案?

请参考先前对此进行的讨论,其中提出了上述解决方案。


编辑。

根据EOF的建议(下面),我检查了sizeof。

在解决方法之前:

sizeof(my_array_t) // Is 4
sizeof(my_array[0]) // Is 4
sizeof(my_array[0].u8) // Is 2

解决方法后:

sizeof(my_array_t) // Is 2
sizeof(my_array[0]) // Is 2
sizeof(my_array[0].u8) // Is 2

这可能意味着这是一个编译器错误。

1
如果 sizeof(union_x) != sizeof(union_x.largest_member),那对我来说看起来像是编译器的错误。 - EOF
1
我不使用XC16,但是通过与其他编译器的类比,我会假设这个舍入是为了与偶地址对齐,从而节省时间。许多编译器都有一个“压缩”结构的选项。这可能会影响计算表中偏移量的有效性。而且,取决于XC16是商业版还是非商业版,付费或免费版本可能会有所不同。 - jcoppens
1
四舍五入是为了与偶地址对齐--这是一个16位的部件。偶地址匹配uint16_t。 - Davide Andrea
1
为了获取CHAR_BIT的值,您需要#include <limits.h>。另外,sizeof(uint8_t)是多少?如果不是1,那么我们就有问题了。 - EOF
2
对我来说,它仍然看起来像是编译器的错误。让我困惑的是解决方法中的 sizeof(my_array[0].u8) == 2。那只是一个 uint8_t,所以它应该有一个 sizeof(uint8_t) == 1 - EOF
显示剩余8条评论
2个回答

5

使用包含两个字节的结构体代替两个字节的数组:

// Two bytes in a 16-bit word
typedef struct{
    uint8_t     lsb;    // As uint8_t, LSB
    uint8_t     msb;    // As uint8_t. MSB
} two_bytes_t;

typedef union {
   uint16_t u16;   // As uint16_t
   two_bytes_t  u8x2; // As 2 each of uint8_t
} my_array_t;


my_array_t my_array[1]; // 1 word array, for testing

my_array[0].u8x2.msb = 1;
my_array[0].u8x2.lsb = 2;

XC16编译器正确地为每个元素分配了仅2个字节,调试器正确地显示了单个字节。

1
优秀的OP回答自己的问题! - Weather Vane
1
我希望你仍然向编译器供应商提交报告。如果只有在这里才能找到解决方法,那就太奇怪了。 - EOF

1

看起来这个问题在编译器中已经修复。我在 XC16 1.26 中检查了一下我的代码(优化级别为0),得到了以下结果:

#include "mcc_generated_files/mcc.h"
#include "stddef.h"

typedef union
{
    uint16_t u16;
    uint8_t u8[2];
} example_1_t;

typedef union
{
    uint16_t u16;

    struct
    {
        uint8_t lsb;
        uint8_t msb;
    };
} example_2_t;

int main(void)
{
    SYSTEM_Initialize();

    size_t typeSize1 = sizeof (example_1_t); // debugger shows 2
    size_t typeSize2 = sizeof (example_2_t); // debugger shows 2

    example_1_t ex1; // Can see all values in debugger
    ex1.u16 = 0x4321; // u8[0] = 0x21, u8[1] = 0x43
    example_2_t ex2; // Can see all values in debugger
    ex2.u16 = 0x4321; // lsb = 0x21, msb = 0x43

    size_t objSize1 = sizeof (ex1); // debugger shows 2
    size_t objSize2 = sizeof (ex2); // debugger shows 2

    while (1)
    {
    }

    return -1;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接