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.