Is it possible to use a character array as a memory pool without violating strict aliasing?
No. The rule in C 2018 6.5 7 says an object defined as array of char
may be accessed as:
- a type compatible with array of
char
,
- a qualified version of a type compatible with array of
char
,
- a type that is the signed or unsigned type corresponding to array of
char
,
- a type that is the signed or unsigned type corresponding to array of
char
,
- an aggregate or union type that includes array of
char
among its members, or
- a character type.
3 and 4 are not possible for array of char
; they apply only when the original type is an integer type. In your various examples with structures, the structures are not types compatible with array of char
(nor are their members), ruling out 1 and 2. They do not include array of char
among their members, ruling out 5. They are not character types, ruling out 6.
I've compiled this code using gcc with -Wstrict-aliasing=3 -fstrict-aliasing, and it works as intended:
The sample output shows that the code produced desired output in one test. This is not equivalent to showing it works as intended.
Is that code safe?
No. The code can be made safe in certain situations. First, declare it with appropriate alignment, such as static _Alignas(max_align_t) memory_pool[256 * 1024];
. (max_align_t
is defined in <stddef.h>
.) That makes the pointer conversions partially defined.
Second, if you are using GCC or Clang and request -fno-strict-aliasing
, the compiler provides an extension to the C language that relaxes C 2018 6.5 7. Alternatively, in some cases, it may be possible to deduce from knowledge of the compiler and linker design that your program will work even if 6.5 7 is violated: If the program is compiled in separate translation units, and the object modules contain no type information or no fancy link-time optimization is used, and no aliasing violation occurs in the translation unit that implements the memory pool, then there cannot be adverse consequences from violating 6.5 7 because no way exists for the C implementation to distinguish code that violates 6.5 7 in regard to the memory pool from code that does not. Additionally, you must know that the pointer conversions work as desired, that they effectively produce pointers to the same addresses (rather than merely intermediate data that can be converted back to the original pointer value but not directly used as a pointer to the same memory).
The deduction that there are no adverse consequences is fragile and should be used with care. For example, it is easy to accidentally violate 6.5 7 in the translation unit implementing the memory pool, as by storing a pointer in a freed memory block or by storing size information in a hidden header preceding an allocated block.