bindgen does this, and in particular bindgen is great because it uses libclang to parse the C header files, so it's interpreting them the same way that clang would.
I'm using bindgen in a project to bind the Linux kernel headers, which makes me a little bit uncomfortable because the Linux kernel is only guaranteed to compile with GCC (and may use GCC-specific extensions in describing structure layout) and in particular there's no guarantee that the in-kernel ABI is stable across different compilers. But it seems to work well in practice, as long as I tell bindgen not to attempt to parse literally everything (which it fails at).
That said - if you're interoperating with memory-mapped IO or with memory mapped from a foreign process, the other thing to be very careful about is that almost all languages (including C!) by default only make sure that memory writes are coherent from the viewpoint of other code in that language, and not necessarily that they're coherent from the viewpoint of something looking directly at memory. It's generally permissible to write a 64-bit number by writing each 32-bit half separately. It's generally permissible to write something and overwrite it immediately, or combine multiple writes, or so forth. In addition to structure layout, you probably want volatile read/write operations, same as you'd want volatile pointers in C: https://doc.rust-lang.org/std/ptr/fn.read_volatile.html or the atomic types with the "SeqCst" barrier https://doc.rust-lang.org/std/sync/atomic/index.html .
You probably won't have too many problems, Google and friends have had a long running project to get the kernel to compile with clang.
Unfortunately, they're not done yet. A guy I bumped into at a Linux kernel conference once said that their main issue is that some people within the kernel project want to keep GCC as the only way to compile the kernel.
I'm using bindgen in a project to bind the Linux kernel headers, which makes me a little bit uncomfortable because the Linux kernel is only guaranteed to compile with GCC (and may use GCC-specific extensions in describing structure layout) and in particular there's no guarantee that the in-kernel ABI is stable across different compilers. But it seems to work well in practice, as long as I tell bindgen not to attempt to parse literally everything (which it fails at).
That said - if you're interoperating with memory-mapped IO or with memory mapped from a foreign process, the other thing to be very careful about is that almost all languages (including C!) by default only make sure that memory writes are coherent from the viewpoint of other code in that language, and not necessarily that they're coherent from the viewpoint of something looking directly at memory. It's generally permissible to write a 64-bit number by writing each 32-bit half separately. It's generally permissible to write something and overwrite it immediately, or combine multiple writes, or so forth. In addition to structure layout, you probably want volatile read/write operations, same as you'd want volatile pointers in C: https://doc.rust-lang.org/std/ptr/fn.read_volatile.html or the atomic types with the "SeqCst" barrier https://doc.rust-lang.org/std/sync/atomic/index.html .