Создать строку в C, где первый символ - длина строки - PullRequest
7 голосов
/ 17 июня 2019

Этот вопрос относится к Объединенному строковому литералу с символьным литералом , но он немного сложнее.

Я хотел бы создать строковый литерал, где первый символ строкидлина строки, а второй символ является константой.Вот как это делается в настоящее время:

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

В идеале я хотел бы заменить его на что-то вроде:

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

Я пытался реализовать это так:

#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");

но он расширяется до:

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

и компилятору не нравится смешивать числа и строки.

Есть ли способ сделать это?

1 Ответ

6 голосов
/ 17 июня 2019

Вы можете на месте определить структуру для хранения префикса и остальных, удобно инициализировать ее, а затем обработать весь 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__)) должен сделать то же самое.

...