首页 > 解决方案 > 在 C 中创建字符串,其中第一个字符是字符串长度

问题描述

这个问题与Concatenate string literal with char literal相关,但稍微复杂一些。

我想创建一个字符串文字,其中字符串的第一个字符是字符串的长度,第二个字符是一个常量。这是目前的做法:

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"};

并且编译器似乎不喜欢混合数字和字符串。

有没有办法做到这一点?

标签: cmacrosc-preprocessor

解决方案


您可以就地定义一个结构来保存前缀和其余部分,方便地对其进行初始化,然后将整体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'
}

编辑:

如果您对填充的可能性感到偏执,这是一种静态断言没有插入的方法:

#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__))应该做同样的事情。


推荐阅读