I'd like to ensure that a given string literal ends up at an address that is a multiple of 2, or even better, 4.
Is there any way to achieve that, preferably without using any compiler-specific extensions? Or is it impossible?
I'd like to do this so the lowermost bits of the string address are 0 and can be (ab)used as tag bits.
In C99 you can do this using a union, for example
#define ALIGNED_STR_UNION(N, S) const union { char s[sizeof S]; int align; } N = { S }
ALIGNED_STR_UNION(sssu, "XYZABC");
Adjust the type int
as necessary.
With that, sssu.s
refers to the characters.
The .s
can be avoided like
#define ALIGNED_STR(S) ((const union { char s[sizeof S]; int align; }){ S }.s)
const char *sss = ALIGNED_STR("XYZABC");
However, this version wastes space on the pointer (including a relative relocation for position independent code) and does not allow declaring static literals in functions.
It is probably better to use the non-standard alignment attributes instead of this.
You can do this using C11 (but not C99). For statically allocated buffers you can use alignas
to do this:
#include <stdio.h>
#include <stdalign.h>
alignas(4) char str[] = "this is aligned to at least 4 bytes";
int main() {
char a;
alignas(4) char str2[] = "and again";
printf("%p\n", &a);
printf("%p\n", str);
printf("%p\n", str2);
}
The trick above is that the string literal is actually being use to initialize a char array of the same size, which lets you use alignas
in the type.
For dynamically allocated ones you use aligned_alloc(size_t alignment, size_t size)
instead of malloc
.
There are other older non-standard ways of doing this which work with GCC/Clang/Intel compilers going back quite some way too, so if you don't have C11 available always you can dress this up with some extra pre-processor work, e.g.:
#if __STDC_VERSION__ >= 201112L
# include <stdalign.h>
# define force_align(x) alignas(x)
#elif defined __GNUC__
# define force_align(x) __attribute__((aligned(x)))
#elif defined __MSC_VER
# define force_align(x) __declspec(align(x))
#else
# error Who are you?
#endif
force_align(128) int x; // Note: maybe your linker doesn't actually support 128 anyway!
Which favours the C11 solution, but uses a GCC specific extension or MSVC one where nothing else suitable exists.