在 C 中创建字符串,其中第一个字符是字符串长度
Create string in C where first character is string length
这个问题与 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"};
并且编译器似乎不喜欢混合数字和字符串。
有什么办法吗?
您可以 in-place 定义一个结构来保存前缀和其余部分,方便地对其进行初始化,然后将整个 struct
视为一个 char
数组(而不是 strict-aliasing 违规,因为标准 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'
}
编辑:
如果您对填充的可能性疑虑重重,这里有一种静态断言 none 已插入的方法:
#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__))
也应该这样做。
这个问题与 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"};
并且编译器似乎不喜欢混合数字和字符串。
有什么办法吗?
您可以 in-place 定义一个结构来保存前缀和其余部分,方便地对其进行初始化,然后将整个 struct
视为一个 char
数组(而不是 strict-aliasing 违规,因为标准 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'
}
编辑:
如果您对填充的可能性疑虑重重,这里有一种静态断言 none 已插入的方法:
#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__))
也应该这样做。