C 如何正确避免;“铸件增加所需的对准度”;读取(2)结构时发出警告?
许多Linux内核接口(inotify等)都是通过C 如何正确避免;“铸件增加所需的对准度”;读取(2)结构时发出警告?,c,system-calls,memory-alignment,C,System Calls,Memory Alignment,许多Linux内核接口(inotify等)都是通过read(2)从某个文件描述符读取结构形式的数据来工作的。这样做的代码通常是这样的: #include <unistd.h> #include <sys/inotify.h> int main() { // all error checking omitted for brevity int inotify_fd = inotify_init(); inotify_add_
read(2)
从某个文件描述符读取结构形式的数据来工作的。这样做的代码通常是这样的:
#include <unistd.h>
#include <sys/inotify.h>
int main() {
// all error checking omitted for brevity
int inotify_fd = inotify_init();
inotify_add_watch(inotify_fd, "file_to_watch", IN_ALL_EVENTS);
char c[4096];
for(;;) {
ssize_t len = read(inotify_fd, c, sizeof(c));
struct inotify_event *s;
for(char* p = c; p < c + len; p += sizeof(struct inotify_event) + s->len) {
s = (struct inotify_event *)p;
// do stuff with s
}
}
}
我第一次尝试修复此警告是修复对齐方式:我尝试使用#include
和alignas(struct inotify_事件)
,但没有成功
我想修复这个警告,而不是让它安静下来。我怎样才能做到
编辑:以下是在inotify fd上读取(2)的工作方式,由以下人员记录:
每次成功读取(2)都会返回一个缓冲区,其中包含一个或多个
以下结构:
struct inotify_event {
int wd; /* Watch descriptor */
uint32_t mask; /* Mask describing event */
uint32_t cookie; /* Unique cookie associating related
events (for rename(2)) */
uint32_t len; /* Size of name field */
char name[]; /* Optional null-terminated name */
};
[……]
此文件名以null结尾,可能包括
进一步的空字节('\0'),以将后续读取与适当的
地址边界
len字段统计名称中的所有字节,包括空字节
字节;因此,每个inotify_事件结构的长度为
sizeof(struct inotify_事件)+len
指定读取的缓冲区(2)太小而无法返回时的行为
关于下一个事件的信息取决于内核版本:in
2.6.21之前的内核,read(2)返回0;从内核2.6.21开始,读取(2)
失败,错误为EINVAL。指定大小为的缓冲区
sizeof(struct inotify_event) + NAME_MAX + 1
将足以读取至少一个事件
我无法读取部分结构,例如从固定大小的片段中分别读取名称。如果我没有指定足够大的缓冲区来读取整个结构,我就不会得到任何缓冲区
union {
char buf[1];
struct some_struct mine;
} b;
确保b.buf和b.mine拥有相同的地址;此外,编译器保证任何所需的对齐。几乎不需要属性扩展(例如alignas),让源代码中没有这种积垢有很大的价值。那么代码应该如何调用
read()
?请注意OP的sizeof(c)
参数。“我该怎么做”实际上取决于如何编写它以使其正常工作,而不仅仅是修复对齐问题。建议发布数据的写入方式。数据根本不是“写入”的。在实际代码中,我不是从stdin(fd 0)中读取,而是从我提到的一个特殊文件描述符中读取,其中调用read()只会使内核将适当的数据复制到buf中,而不会发生任何相应的write()。特殊的文件描述符将用于文档布局。尽可能发布/链接与特殊文件描述符相关的信息。或者只使用联合
技巧。@chux inotify就是这样一种特殊的FD。我将请求的信息编辑到问题中。使用expectchar buf[1]代码>-->charbuf[4096]代码>。作为稳健错误检查的一部分,确保read()
返回值在s->len
中有意义。
union {
char buf[1];
struct some_struct mine;
} b;