【发布时间】:2019-11-08 15:18:03
【问题描述】:
在网上浏览代码的时候,经常看到sn-ps是这样的:
struct epoll_event event;
memset(&event, 0, sizeof(event));
这种模式对我来说似乎没有必要,如果事件被完整填写,但它很普遍。也许是为了考虑到结构未来可能发生的变化?
【问题讨论】:
在网上浏览代码的时候,经常看到sn-ps是这样的:
struct epoll_event event;
memset(&event, 0, sizeof(event));
这种模式对我来说似乎没有必要,如果事件被完整填写,但它很普遍。也许是为了考虑到结构未来可能发生的变化?
【问题讨论】:
这肯定只是糟糕的复制粘贴编码。 The man page for epoll 没有记录对 epoll_event 结构进行零初始化的任何需要,并且在示例中也没有这样做。未来对结构的更改似乎是不可能的(ABI),但如果是这样,合同显然会是与您请求的events 无关的结构的任何部分将被忽略(甚至不阅读,因为调用者可能传递了一个指向存储的指针,该指针未超出原始定义)。
此外,一般来说,当结构应该被零初始化时,使用memset 充其量是毫无意义的,最坏的情况是不正确/不可移植,因为零表示不一定是零值(对于指针和浮点类型)。如今,这种普遍性主要是历史上的好奇心,无论如何与epoll这样的Linux特定接口无关,但它也出现在mbstate_t中,它存在于完全通用的C语言中,并且需要零初始化才能正确使用相关的接口。对需要零值而不是全零字节表示的事物进行零初始化的正确方法是使用通用零初始化器{ 0 }。
【讨论】:
struct epoll_event 中添加字段,例如data 成员之后的新字段?
像这样使用 memset 可以帮助您更快地定位错误。将其视为一种防御性(甚至安全)的编程风格。
假设您没有使用 memset,而是尝试按照 API 记录的方式认真填写每个成员。但是,如果您忘记填写一个字段(或后来的 API 更改导致添加一个新字段),那么该字段在运行时采用的值是未定义的;并且在实践中将使用之前持有的任何内存。
后果是什么?
如果你很幸运,你的代码会立即以一种可以调试的方式失败,例如,如果未设置的字段需要一个高度具体的值。
如果您不走运,您的代码可能仍然有效,并且可能工作多年。也许在您当前的操作系统上,程序内存不知何故已经保存了 API 预期的正确值。但是,当您跨系统和编译器移动代码时,会出现令人困惑的行为:“它可以在我的机器上运行,但我不明白为什么它不能在您的机器上运行”。
所以在这种情况下,memset 正在帮助您避免这种不确定的行为。
当然,您仍然可以分析您的代码、检查未定义的内存、单元测试等。执行 memset 并不能替代这些。这只是获得安全软件的另一种技术。
【讨论】: