Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将字节数组复制到C中的union/struct中:是什么使我的对齐偏离了方向?_C_Struct_Arm_Microcontroller_Unions - Fatal编程技术网

将字节数组复制到C中的union/struct中:是什么使我的对齐偏离了方向?

将字节数组复制到C中的union/struct中:是什么使我的对齐偏离了方向?,c,struct,arm,microcontroller,unions,C,Struct,Arm,Microcontroller,Unions,我正在为PSoC5LP微控制器(ARM Cortex-M3)编写一些代码,它从串行端口接收字节数组,并将它们保存到一个充满配置变量的结构中。我似乎在对齐方面遇到了问题,我无法找出根本原因 我正在使用的结构(以及我正在使用的枚举)定义如下: typedef enum{ MODE_NIGHT = 0x00, MODE_DAY = 0x01, MODE_DUAL = 0x02 }daymode_t; typedef enum{ BRT_MIN = 0x00,

我正在为PSoC5LP微控制器(ARM Cortex-M3)编写一些代码,它从串行端口接收字节数组,并将它们保存到一个充满配置变量的结构中。我似乎在对齐方面遇到了问题,我无法找出根本原因

我正在使用的结构(以及我正在使用的枚举)定义如下:

typedef enum{
    MODE_NIGHT = 0x00,
    MODE_DAY = 0x01,
    MODE_DUAL = 0x02
}daymode_t;

typedef enum{
    BRT_MIN = 0x00,
    BRT_MAX = 0x01,
    BRT_CUSTOM = 0x02,
    BRT_RECALL = 0x03
} startbrtmode_t;

typedef enum{
    SWITCH_MIN = 0x00,
    SWITCH_MAX = 0x01,
    SWITCH_RECALL = 0x02,
    SWITCH_CUSTOM = 0x03,
    SWITCH_EQUAL = 0x04
} switchbrtmode_t;

#define BACKLIGHT_CONFIG_SIZE   31
typedef union {
    struct{
        uint16_t        num_steps;          //2
        uint8_t         iadj_day;           //1
        uint8_t         iadj_night;         //1
        float           min_dc_day;         //4
        float           min_dc_night;       //4
        float           max_dc_day;         //4
        float           max_dc_night;       //4
        daymode_t       daymode_default;    //1
        bool            daymode_recall;     //1
        startbrtmode_t  startbrt_default;   //1
        uint16_t        startbrt_step;      //2
        switchbrtmode_t switchbrt_default;  //1
        uint16_t        day_switchstep;     //2
        uint16_t        night_switchstep;   //2
        bool            nonlinear;          //1
    };
    uint8_t bytes[BACKLIGHT_CONFIG_SIZE];
} backlightconfig_t;
想法是我可以(通过CRC验证接收后)简单地memcpy()将接收到的字节直接放入结构中,这要感谢union:

backlightconfig_t bl_in;
memcpy(bl_in.bytes, message_in, BACKLIGHT_CONFIG_SIZE);
然而,当我这样做的时候,我最终得到了一些看似“改变”的价值观。我制作了一个电子表格,用于跟踪字节的去向、接收内容以及结束位置:

我看到的是,在startbrtmode_t枚举关闭后,我的字节看起来像是被关闭了。我的用于startbrt_步骤的0x0005看起来完全被吃掉了(我通过调试器确认它存在于字节数组中,但它没有显示在结构成员中)?我没能弄清楚为什么会发生这种事。我认为可能是编译器(ARM GCC 5.4-2016)为枚举保留了太多的空间,但是sizeof(startbrtmode_t)返回1。事实上,我已经在使用不同的结构/联合时没有任何问题了,但这是一个完全由单个字节填充的结构,所以我想这一定与键入有关?如果您对正在发生的事情有任何想法,我们将不胜感激


谢谢

试着用
#pragma pack(1)
/
#pragma pack()


尝试使用
#pragma pack(1)
/
#pragma pack()


这是因为您无法保证字段在结构中是如何对齐或填充的
startbrt\u step
是一个
uint16\u t
字段,因此,在某些体系结构上,它可能需要2字节对齐

假设
offsetof(backgroundconfig\u t,startbrt\u default)==22
就像您假设的那样,那么
startbrt\u步骤将从第23个字节开始,该字节未在2个字节边界上对齐,因此插入一个填充字节

--------------------------
 22     startbrt_default
--------------------------
 23     * padding *
--------------------------
 24     startbrt_step
--------------------------
如果将所有2字节字段放在浮点字段之后,可能会解决问题,但无论如何,解决方案都是脆弱的


您可以使用一些预处理器宏强制对齐到1字节边界,但这不能保证在某些体系结构上工作(如果您尝试访问未对齐的内存,则某些ARM将中止),或者这可能会增加性能损失。

这是因为您无法保证在结构中如何对齐或填充字段
startbrt\u step
是一个
uint16\u t
字段,因此,在某些体系结构上,它可能需要2字节对齐

假设
offsetof(backgroundconfig\u t,startbrt\u default)==22
就像您假设的那样,那么
startbrt\u步骤将从第23个字节开始,该字节未在2个字节边界上对齐,因此插入一个填充字节

--------------------------
 22     startbrt_default
--------------------------
 23     * padding *
--------------------------
 24     startbrt_step
--------------------------
如果将所有2字节字段放在浮点字段之后,可能会解决问题,但无论如何,解决方案都是脆弱的


您可以使用一些预处理器宏强制对齐到1字节边界,但这不能保证在某些体系结构上工作(如果您尝试访问未对齐的内存,则某些ARM会中止)或者它可能会增加性能损失。

电子表格中的错误在于
enum
s不简单地使用包含其值的最窄类型。根据GCC手册,如果没有负值,则与
enum
兼容的整数类型为
unsigned int
,否则为
int

如果对小的
enum
使用四个字节是不可接受的,请使用适当的整数类型声明该字段,并仅使用
enum
作为它提供的常量。请注意,所有常量都在该类型的范围内

(现代)C++允许<>代码>枚举> /Cord>声明指定它们使用的基本整数类型,因此猜测较少;如果你想要一个字节大小的枚举,你可以在C++中请求这个。 您的MODE DFLT变量#20可能只适合您,因为系统是小端,因此

enum
的最低有效字节位于正确的偏移量。此外,您可能测试了后面两个变量的零值,即模式调用和启动BRT DFLT,所以您没有注意到它们对模式DFLT的影响

如果不确定偏移量,请编制一个测试程序,打印偏移量并调整每个结构杆件的大小:

#include <stdio.h>
#include <time.h>
#include <stddef.h>

/* typeof is a GCC extension */

#define OFSZ(type, memb) (printf("%s: size = %d, offset = %d\n", \
                                 #memb,\
                                 (int) sizeof(typeof(((type *) 0)->memb)),\
                                 (int) offsetof(type, memb)))


int main()
{
  OFSZ(struct tm, tm_year);
  OFSZ(struct tm, tm_sec);
  return 0;
}

$ ./ofs
tm_year: size = 4, offset = 20
tm_sec: size = 4, offset = 0
#包括
#包括
#包括
/*typeof是一个GCC扩展*/
#定义OFSZ(类型,memb)(printf(“%s:size=%d,offset=%d\n”\
#memb\
(int)sizeof(typeof(((type*)0)->memb))\
(内部)偏移量(类型,内存)
int main()
{
OFSZ(结构tm,tm年);
OFSZ(结构tm,tm_-sec);
返回0;
}
美元/小时
tm_年:尺寸=4,偏移=20
tm_秒:大小=4,偏移=0

电子表格中的错误在于
enum
s不简单地使用包含其值的最窄类型。根据GCC手册,如果没有负值,则与
enum
兼容的整数类型为
unsigned int
,否则为
int

如果对小的
enum
使用四个字节是不可接受的,请使用适当的整数类型声明该字段,并仅使用
enum
作为它提供的常量。请注意,所有常量都在该类型的范围内

(现代)C++允许<>代码>枚举> /Cord>声明指定它们使用的基本整数类型,因此猜测较少;如果你想要一个字节大小的枚举,你可以在C++中请求这个。 模式DFLT变量#20可能只适合您,因为系统是little endian