我在以下使用结构的公司中是新手:
uint16 len
我知道有关对齐和填充的一些事情,我认为编译器(ARM9设备的gnu C99)将添加一些填充以使结构对齐。
但这段代码安全吗?
据我了解,只要int8 array[]
变量紧跟{{1}}个变量,无论其他结构成员如何,它都是安全的。
它只会在uint16之前添加填充,前面的大小是奇数吗? 这个用法是否正确?更重要的是,它安全吗?
答案 0 :(得分: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写的东西。
要回答你的评论,将它们打包是错误的解决方法。因为它会使成员错位,只会打开another can of worms。
还要警惕自定义固定大小的typedef。我曾经有过在typedef char int8;
s char
...
unsigned
的乐趣
答案 1 :(得分: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之前添加填充,前面的大小是奇数吗?
这由编译器决定。它可能受到编译指示,命令行选项,配置选项,语言扩展(虽然这些都没有在示例中使用),目标体系结构或编译器想要用于做出此类决策的任何其他内容的影响。
这种用法是否正确?
据我所知,该计划符合规定,如果这就是你的意思。
更重要的是,它安全吗?
程序的输出无法单独从其代码中预测,因此从这个意义上说,不,它不安全。