结构对齐安全使用

lea*_*rog 5 c struct c99 arm9 struct-member-alignment

我是一家新公司,在这家公司中完成了以下结构的使用:

#include <stdio.h>
#include <string.h>

typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned short int uint16;
typedef signed short int int16;

typedef struct padded_t {
    int8 array0[11];
    int8 array1[4];
    uint16 len2;
    int8 array2[25];
    uint16 len3;
    int8 array3[6];
    // many more len/arrays follow
} padded_t;

int main(int argc, char** argv)
{
    padded_t foo;
    memset((void*)&foo, 0, sizeof(padded_t));

    int8* str = "foobar";
    int16 size = (int16)strlen(str);

    int8* ptr = (int8*)&foo.len2;

    // please note that the memcpy references only the pointer to len
    // are the following couple of lines safe?
    memcpy ((void*)ptr, &size, 2);
    memcpy ((void*)&ptr[2], (void*)str, size);

    printf("%d\n", foo.len2);
    printf("%s\n", foo.array2);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我知道有关对齐和填充的一些事情,我假设编译器(ARM9设备的gnu C99)将添加一些填充以使结构对齐.

但这段代码安全吗?
据我了解,只要uint16 len变量紧跟int8 array[]变量后,无论其他结构成员如何,它都是安全的.

当它之前的大小是奇数时,它是否只会在uint16之前添加填充?
这个用法是否正确?更重要的是,它安全吗?

Joh*_*ger 2

但这段代码安全吗?

据我了解,只要uint16 len变量后面紧跟着int8 array[]变量,无论其他结构成员如何,它就是安全的。

从某种意义上说,它是不安全的,因为允许编译器自由地在结构成员之间或之后插入任意数量的填充,因此您不能确信 指向 的&ptr[2]第一个字节foo.array2。然而,假设uint16确实是两个字节宽(语言无法保证这一点),您可以确信如果size小于 25,则

memcpy ((void*)&ptr[2], (void*)str, size);
Run Code Online (Sandbox Code Playgroud)

既不会修改 的任何字节foo.len2,也不会修改 的最后一个字节foo.array2。由于foo之前已填充零,因此这将foo.array2作为正确终止的 C 字符串留下。因此,使用 打印它是安全的printf()。另一方面,C 并不保证这样做的结果将与打印的结果相同str

当 uint16 之前的大小为奇数时,它只会在 uint16 之前添加填充吗?

这是由编译器自行决定的。它可能会受到编译指示、命令行选项、配置选项、语言扩展(尽管示例中没有使用这些)、目标体系结构或编译器想要用来做出此类决策的任何其他内容的影响。

这种用法正确吗?

据我所知,该程序是符合要求的,如果这就是你的意思。

更重要的是,它安全吗?

该程序的输出无法仅从其代码中预测,因此从这个意义上说,不,它是不安全的。