这个memset-memcmp对结构变量有效吗?

时间:2017-12-27 14:20:56

标签: c undefined-behavior unspecified-behavior

memset结构符合某些值是否合法,然后将其与memcmp进行比较?

struct S {
    // struct definition not relevant, but it has bitfields
};

struct S invalid_S;
memset(&invalid_S, 0xFF, sizeof invalid_S);

struct S value;
memset(&value, 0, sizeof value); // actual data read would be here

if (memcmp(&invalid_S, &value, sizeof(struct S) != 0) {
    /// operate on fields of value
}

struct S value2;
value2 = invalid_S;

if (memcmp(&invalid_S, &value2, sizeof(struct S) != 0) {
    /// operate on fields of value, which doesn't happen now
}

以上代码行为是否定义良好,未定义或实现指定?上述代码的有效性是否取决于struct S

将结构填充为0xFF,然后将其与memcmp进行比较的原因是:我有一个函数返回一个与我从硬件设备读取的bitfield结构相匹配的结构,没有浪费的位或字节,我想要一种报告错误的有效方法(设备永远不会返回所有0xFF字节)。我有固定的平台和工具链,代码现在可以使用,但是如果我提高优化级别,我可以相信它不会中断吗?

结论:虽然如果我确定没有填充位,浮点字段等可能有问题,这个代码可以工作,但我决定只将一个特定的结构字段设置为特定的“不可能”值来指示错误。

2 个答案:

答案 0 :(得分:3)

你说该函数返回一个“位域结构”。如果你真的返回一个结构,即按值返回一个结构,那么不行,并不能保证你想要的行为。复制结构时,实现只需要在其成员中重现值,而不是其表示中的实际字节。

同样适用于您的第value2 = invalid_S;行。

答案 1 :(得分:1)

  

将结构体设置为某个值是否合法,然后将其与memcmp进行比较?

是的,因为所有memsetmemcmpmemcpy都记录在任意内存区域(假设指针和传递给它们的大小指向有效的内存区域) )。

但是,在某些情况下,这可能没有意义。例如,如果您从某些未初始化的内存中memcpy,则会在目标中获得垃圾,并且使用该垃圾可能是undefined behavior

您正在memset使用0xff。从理论上讲,你可能有一些char大于8位的实现(但实际上这种情况不会发生,所以你不关心)。

理论上你可能有一些实现具有整数值的陷阱表示。在实践中,这种情况不会发生。

如果您对padding可能无法正常工作的结构使用memcmp。您可能希望深入了解平台的ABI规范,以了解它们的实现方式(并且可能未在ABI中指定位域并且特定于编译器)。

我相信在实践中,您需要使用特定的编译器很好地理解特定struct的确切布局。看起来您的代码可能是特定于硬件的,那么您对可移植性并不在意。所以在实践中你的struct S 非常相关(也许避免其中的位域会“更安全”)。