4 ms·
there are ways around this, if VLAs are allowed. // in <opaque_foo.h> typedef struct opaque_foo opaque_foo_t; size_t opaque_foo_sz(void); void opaque
by cozzyd 3y ago
there are ways around this, if VLAs are allowed.
// in <opaque_foo.h>
typedef struct opaque_foo opaque_foo_t;
size_t opaque_foo_sz(void);
void opaque_foo_init(opaque_foo_t* foo)
// in your code, which you could write a helper macro for if you were so inclined
char opaque_foo_mem[opaque_foo_sz()];
opaque_foo_t * my_foo = (opaque_foo_t*) opaque_foo_mem;
opaque_foo_init(my_foo);
- kopecs 3y agoDoesn't this violate strict aliasing?
- cozzyd 3y agoyes, though you can fix that with compiler flags (or, #pragma if you want strict aliasing elsewhere in your code) alternatively, gcc supports VLAs in unions, but I don't think clang does, but that makes it extra annoying to do. edit: apparently you can probably apply the may_alias attribute to the type? Or you could try using transparent_union. No idea if clang supports either...
- mananaysiempre 3y agoAt that point, it is IMO better to obtain that block from alloca()[1]—it’s not standard, but where it’s available the compiler will treat the result as untyped for the purposes of aliasing. (If you’re on GCC/LLVM, __builtin_alloca_with_align is also an option, although note that the memory it returns may not outlive the current block—similar to a standard automatic variable, but unlike memory from traditional alloca.) ISO C has a gigantic hole when it comes to obtaining and recycling untyped memory, pretending the hole is not there isn’t going to help. [1] https://nullprogram.com/blog/2019/10/28/ https://nullprogram.com/blog/2019/10/28/, discussed at the time at https://news.ycombinator.com/item?id=21374863 https://news.ycombinator.com/item?id=21374863
- jenadine 3y agoAnd alignment?
- cozzyd 3y agoyes, you may need an alignas depending on platform (though you probably want it even if unaligned access is supported).
- kazinator 3y agoJust use alloca. // in your code, which you could write a helper macro for if you were so inclined opaque_foo_t *my_foo = alloca(opaque_foo_sz()); opaque_foo_init(my_foo);
- bensecure 3y agochar* can alias anything
- cozzyd 3y agoThe strict aliasing optimization in gcc in theory can cause problems (which is why many, including the Linux kernel, disable that)
- deleted 3y ago[deleted]
- menaerus 3y agoThis approach violates alignment requirements causing misaligned accesses that on some architectures is mitigated by generating extra instructions while on some other architectures it's a violation (e.g. segfault). There is no way for a compiler to infer the alignment requirement of a struct because it does not see its definition. You would always have to align the char buffer by hand but you cannot do it for the same reason compiler cannot. What you can do is to always greedily align the char buffer to the strictest (largest) fundamental requirement for that platform - in other words alignas(max_align_t). And this is actually what alloca() does for you by default. From https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html > The object is aligned on the default stack alignment boundary for the target determined by the BIGGEST_ALIGNMENT_macro.