to convert a string to a pascal string type
To convert a string literal, _Generic
and compound literal will get close to OP objective.
For a better solution, more details and example use cases would help illustrate OP's goal.
#define P_STRING_CONV(X) _Generic((X)+0, \
char *: &((struct {char len; char s[sizeof(X)-1]; }){ (char)(sizeof(X)-1), (X) }).len \
)
void dump(const char *s) {
unsigned length = (unsigned char) *s++;
printf("L:%u \"", length);
while (length--) {
printf("%c", *s++);
}
printf("\"\n");
}
int main(void) {
dump(P_STRING_CONV(""));
dump(P_STRING_CONV("A"));
dump(P_STRING_CONV("AB"));
dump(P_STRING_CONV("ABC"));
return 0;
}
Output
L:0 ""
L:1 "A"
L:2 "AB"
L:3 "ABC"
@Jonathan Leffler recommended that the created pascal-like string also contain a terminating null character. To do so with above code, simple change sizeof(X)-1
into sizeof(X)
. Then by accessing the pascal_like_string + 1
, code has a pointer to a valid C string.
(X)+0
converts an array type to a pointer
sizeof(X)-!!sizeof(X)
produces a size of the string literal, not counting its \0. At least 1.
struct {char len; char s[sizeof(X)-!!sizeof(X)]; }
Is a right-sized pascal-like structure.
(struct {char len; char s[sizeof(X)-!!sizeof(X)]; }){ (char)(sizeof(X)-1), (X) }
is a compound literal.
The following will convert a C string to a pascal like string. Note that as a pascal like string, there is no '\0'
.
#include <limits.h>
#include <stdlib.h>
#include <string.h>
char *pstring_convert(char *s) {
size_t len = strlen(s);
assert(len <= UCHAR_MAX);
memmove(s+1, s, len);
s[0] = (char) (unsigned char) len;
return s;
}