5

我是一家公司的新手,该公司完成了以下结构的使用:

#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;
}

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

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

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

4

2 回答 2

3

您不需要编写适用于每个系统的代码。您应该做的是编写具有可预测行为的代码。它要么按设计工作,要么如果您的假设不成立,则静态断言会中止编译。

第二memcpy行没有做到这一点。它假定offsetof(struct padded_t, len2) + 2 == offsetof(struct padded_t, array2). 一个经常成立但完全愚蠢的假设。

为什么不直接写

foo.len2 = strlen(str);
memcpy (foo.array2, str, foo.len2);
//possibly, foo.array2[foo.len2] = '\0';

代码可读。没有不需要的变量。没有不必要的演员表。没有不可预测的行为。原始代码看起来不像你会从中学到很多东西的代码,混乱看起来不像我期望精通 C 的人编写的东西。

要回答您的评论,将它们打包是错误的解决方法。因为它会错位成员,只会打开另一罐蠕虫

还要警惕自定义固定大小的 typedef。我曾经有过在一个有stypedef char int8;的系统上调试 a 的乐趣……</p> charunsigned

于 2016-08-10T18:22:36.407 回答
2

但是这段代码安全吗?

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

从某种意义上说,允许编译器在结构成员之间或之后插入任意数量的填充是不安全的,因此您不能确信&ptr[2]指向foo.array2. 但是,如果它uint16确实是两个字节宽(语言绝不保证),您可以确信如果size小于 25,那么

memcpy ((void*)&ptr[2], (void*)str, size);

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

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

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

这种用法正确吗?

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

更重要的是,它安全吗?

程序的输出不能仅从其代码中预测,所以从这个意义上说,不,它是不安全的。

于 2016-08-10T18:30:52.040 回答