7

This question is related to Concatenate string literal with char literal, but is slightly more complex.

I would like to create a string literal, where the first character of the string is the length of the string, and the second character is a constant. This is how it is being done currently:

const char myString[] = 
{
    0x08,
    SOME_8_BIT_CONSTANT,
    'H',
    'e',
    'l',
    'l',
    'o',
    0x00
};

Ideally, I would like to replace it with something like:

const char myString[] = BUILD_STRING(0xAA, "Hello");

I tried implementing it like this:

#define STR2(S) #S
#define STR(S) STR2(S)
#define BUILD_STRING(C, S)  {(sizeof(S)+2), C, S}

const char myString[] = BUILD_STRING(0xAA, "Hello");

but it expands to:

const char myString[] = {(sizeof("Hello")+2), 0xAA, "Hello"};

and the compiler doesn't seem to like mixing numbers and strings.

Is there any way to do this?

7
  • Hm in your example, the string length is 7, not 8. Commented Jun 17, 2019 at 16:34
  • 3
    The C preprocessor has no way to determine a string length. If you use sizeof you are no longer in pre-processing stage: might as well write a proper function. Commented Jun 17, 2019 at 16:40
  • like a "\pPascal String"? Commented Jun 17, 2019 at 16:57
  • 4
    @pmg Right but the OP doesn’t require this to be done at the preprocessor stage. All they require is for it to be done at compile time. Case in point, if there were a way of performing macro transformation from BUILD_STRING(C, "foo"); to {sizeof "foo" + 2, C, "foo"[0], "foo"[1], …} then that would fulfil OP’s requirements. I don’t think there’s a way but maybe I’m missing something. Commented Jun 17, 2019 at 17:14
  • 1
    @pmg sizeof will be evaluated at compile time (except in the case of VLAs, which isn't relevant here), so it still satisfies OPs requirements. Commented Jun 17, 2019 at 22:35

1 Answer 1

6

You could in-place define a structure to hold the prefix and the rest, conveniently initialize it, and then treat the whole struct as a char array (not a strict-aliasing violation because standard C lets you treat any object as a char array).

Technically, you're not guaranteed that the compiler won't insert padding between the prefix and the rest, but in practice you can count on it.

#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:

If you're paranoid about the possibility of padding, here's one way to statically assert none is inserted:

#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})

Alternatively, using the first version with the (nonstandard) __attribute((__packed__)) should do the same.

Sign up to request clarification or add additional context in comments.

9 Comments

Can you use compiler extensions for attributes to declare the struct as having packed layout?
@KonradRudolph __attribute((__packed__)). Sure. Seems unnecessary, though. Sane compilers don't pad if they don't need to.
@KonradRudolph It'd be more inclined to pack a static assertion in there asserting no padding (=> no nonstandard stuff).
After trying for a while to come up with a pure preprocessor way (no luck), I think this is the only way to do this at compile time. The asserts will make sure it doesn't break by mistake.
@CoffeeTableEspresso I'd be very surprised if there was another way.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.