简体   繁体   中英

How to correctly avoid "cast increases required alignment" warning when read(2)ing structs?

A lot of Linux kernel interfaces (inotify, etc.) work by read(2) ing data in the form of a struct from some file descriptor. The code to do so often goes something like this:

#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
                }
        }
}

When I compile the above with clang, I get this warning:

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;
                            ^~~~~~~~~~~~~~~~~~~~~~~~~

My first attempt to fix this warning was to fix the alignment: I tried using #include <stdalign.h> and alignas(struct inotify_event) , to no avail.

I'd like to actually fix this warning, not just silence it. How can I do so?

EDIT: Here's how read(2) on an inotify fd works, as documented by its man page :

Each successful read(2) returns a buffer containing one or more of the following structures:

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

[...]

This filename is null-terminated, and may include further null bytes ('\\0') to align subsequent reads to a suitable address boundary.

The len field counts all of the bytes in name, including the null bytes; the length of each inotify_event structure is thus sizeof(struct inotify_event)+len.

The behavior when the buffer given to read(2) is too small to return information about the next event depends on the kernel version: in kernels before 2.6.21, read(2) returns 0; since kernel 2.6.21, read(2) fails with the error EINVAL. Specifying a buffer of size

sizeof(struct inotify_event) + NAME_MAX + 1

will be sufficient to read at least one event.

I can't read partial structs, such as reading the name separately from the fixed-size piece. If I don't specify a big enough buffer to read an entire struct, I don't get any of it.

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

Ensures that b.buf and b.mine have the same address; furthermore, any required alignment is guaranteed by the compiler. There is almost never a need for the attribute extensions (eg. alignas), and a lot of value in having source free of that crud.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM