许多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_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
}
}
}
当我用clang编译上面的代码时,收到以下警告:
inotify.c:13:15: warning: cast from 'char *' to 'struct inotify_event *' increases required alignment from 1 to 4 [-Wcast-align]
s = (struct inotify_event *)p;
^~~~~~~~~~~~~~~~~~~~~~~~~
我纠正此警告的第一个尝试是修复对齐方式:我尝试使用#include <stdalign.h>
和alignas(struct inotify_event)
,但无济于事。
我想实际解决此警告,而不仅仅是保持沉默。我该怎么办?
编辑:its man page记录了inotify fd的read(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字段计算名称中的所有字节,包括null 字节;因此,每个inotify_event结构的长度为 sizeof(struct inotify_event)+ len。
赋予read(2)的缓冲区太小而无法返回的行为 关于下一个事件的信息取决于内核版本: 2.6.21之前的内核,read(2)返回0;从内核2.6.21开始,read(2) 失败,并显示错误EINVAL。指定大小的缓冲区
sizeof(struct inotify_event) + NAME_MAX + 1
足以阅读至少一个事件。
我无法读取部分结构,例如与固定大小的部分分开读取名称。如果我没有指定足够大的缓冲区来读取整个结构,那么我什么也得不到。
答案 0 :(得分:0)
union {
char buf[1];
struct some_struct mine;
} b;
确保b.buf和b.mine具有相同的地址;此外,编译器可以保证任何所需的对齐方式。几乎不需要属性扩展(例如alignas),并且使源中没有任何杂物就具有很多价值。