读取(2)结构时,如何正确避免出现“铸件增加所需对齐的警告”?

时间:2018-09-16 00:14:40

标签: 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_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
     

足以阅读至少一个事件。

我无法读取部分结构,例如与固定大小的部分分开读取名称。如果我没有指定足够大的缓冲区来读取整个结构,那么我什么也得不到。

1 个答案:

答案 0 :(得分:0)

union {
     char    buf[1];
     struct some_struct mine;
} b;

确保b.buf和b.mine具有相同的地址;此外,编译器可以保证任何所需的对齐方式。几乎不需要属性扩展(例如alignas),并且使源中没有任何杂物就具有很多价值。