Вы можете на месте определить структуру для хранения префикса и остальных, удобно инициализировать ее, а затем обработать весь struct
как массив char
(не нарушение строгого псевдонима, потому что стандартный C позволяет вам обрабатывать любой объект как массив char
).
Технически, вы не гарантированы, что компилятор не вставит отступ между префиксом и остальными, но на практике вы можете рассчитывать на это.
#define BUILD_STRING(C, S) \
((char const*)&(struct{ char const p[2]; char const s[sizeof(S)]; })\
{ {(sizeof(S)+2), C}, S})
const char *myString = BUILD_STRING(0xAA, "Hello");
#include <stdio.h>
int main()
{
printf("%d, %#hhX, '%s'\n", myString[0], myString[1], myString+2);
//PRINTS: 8, 0XAA, 'Hello'
}
Edit:
Если вы недовольны возможностью заполнения, вот один из способов статически утверждать, что ни один не вставлен:
#define BUILD_STRING__(S) \
char const p[2]; char const s[sizeof(S)]
#define BUILD_STRING(C, S) \
((char const*)&(struct{BUILD_STRING__(S); \
_Static_assert(sizeof(S)+2== \
sizeof(struct{BUILD_STRING__(S);_Static_assert(1,"");}),""); \
}){ {sizeof(S)+2, C}, S})
В качестве альтернативы, используя первую версию с (нестандарт)
__attribute((__packed__))
должен сделать то же самое.