2017-01-23 126 views
2
struct something { 
    uint32_t a; 
    uint8_t b; 
    uint16_t c; 
    uint32_t x; 
    uint16_t y; 
    uint8_t z; 
}; 

uint8_t *data = malloc(14); 
struct something *s = (struct something *)data; 

s->a = 1; 
s->b = 2; 
s->c = 3; 
s->x = 4; 
s->y = 5; 
s->z = 6; 

在C或结构填充中执行此操作总是安全可能会导致问题吗?保证数据[0] ..数据[3] == 1,数据[4] == 2,数据[5] ..数据[6]数据[3] == 1,数据[4] == 3, == 3,data [7] .. data [10] == 4,data [11] .. data [12] == 5和data [13] == 6?C结构填充问题

编辑2:上编辑1

+1

你是否检查了'sizeof'这个'struct'ure? –

+1

不,它不安全。填充*会*成为问题。 –

+1

编辑之后的评论:不,这不是因为可能的填充。 –

回答

10

这个小错误是安全运行。编译器将以实现定义的方式添加填充。

一般来说,一个给定尺寸的构件将上一对齐偏移是大小的倍数。

鉴于典型方式填充完成,这struct将最有可能在16个字节大小。物理布局很可能(但不一定)如下所示:

struct something { 
    uint32_t a;   // offset 0 
    uint8_t b;   // offset 4 
         // 1 byte padding 
    uint16_t c;   // offset 6 
    uint32_t x;   // offset 8 
    uint16_t y;   // offset 12 
    uint8_t z;   // offset 14 
    // 1 byte padding 
}; 

请勿使用幻数。 Intead,请使用sizeof运营商。

struct something *s = malloc(sizeof(struct something)); 

编辑:

如果你想提高你的struct设计了一个特殊的方式的机会,看到这个guide to structure packing。如果你遵循这里的做法,那么很有可能(但不是100%)你的struct将按照你的期望被记忆。

对于gcc,您可以使用__attribute__((packed))上的struct删除struct的填充。但是,这样做可能会导致性能损失或可能导致页面错误。 -Wpadded-Wpacked选项也可以告诉你更多关于填充。

+1

但是,如果有这样的排序和消除填充是一个**要求**,那么您的编译器_may_有工具可以帮助您(但您付出了可移植性损失并可能是性能损失)。 –

+0

这些偏移量是否会反映存储在“数据”变量中的数据?我编辑这个问题来说清楚。我的意思是,编译器是否足够智能以绕过由填充引起的问题? –

+0

@RafaelAlmeida,没有问题是由填充造成的,除非你做了明确依赖于填充位置或数量的东西。需要做这样的事情是不常见的。没有这样做的程序严格符合标准。取决于关于存储器偏移的假设,除了第一个与结构的开始相关的结构成员之外,例如您在编辑中询问的内容,正是这种不合格的事情。 –

2

硬编码14 非常调皮

你为什么不使用sizeof(struct something)呢?这是一个编译时可评估的常量表达式,因此不存在运行时开销。

你的预感是正确的:一个编译器保留插入结构元件之间填充,以及在最终元件的端部的右侧。 (请注意,第一个元素的地址必须是一样的struct的地址虽然)。