代码之家  ›  专栏  ›  技术社区  ›  Joseph Sible-Reinstate Monica

如何正确避免读取(2)结构时出现“强制转换增加所需对齐”警告?

  •  -1
  • Joseph Sible-Reinstate Monica  · 技术社区  · 6 年前

    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) ,但毫无用处。

    我想修正这个警告,而不仅仅是让它沉默。我该怎么做?

    编辑:下面是关于inotify fd的read(2)是如何工作的,如 its man page :

    以下结构:

           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 */
           };
    

    此文件名以空结尾,可能包括 地址边界。

    len字段统计名称中的所有字节,包括null 字节;因此,每个inotify事件结构的长度

    当给读取(2)的缓冲区太小而无法返回时的行为 在2.6.21之前的内核,read(2)返回0;在内核2.6.21之后,read(2) 失败,出现错误EINVAL。指定大小为的缓冲区

    sizeof(struct inotify_event) + NAME_MAX + 1
    

    将足以读取至少一个事件。

    我无法读取部分结构,例如从固定大小的文件中单独读取名称。如果我没有指定一个足够大的缓冲区来读取整个结构,我就不会得到任何缓冲区。

    1 回复  |  直到 6 年前
        1
  •  0
  •   mevets    6 年前
    union {
         char    buf[1];
         struct some_struct mine;
    } b;
    

    确保b.buf和b.mine具有相同的地址;此外,编译器保证任何所需的对齐。几乎不需要属性扩展(例如alignas),并且让源代码不受crud的影响有很大的价值。