C宏将字符串转换为pascal字符串类型
我想要一个宏将预处理器定义的字符串转换为pascal类型的字符串,然后能够使用宏来初始化常量字符数组等等。C宏将字符串转换为pascal字符串类型
像这样的事情将是巨大的:
#define P_STRING_CONV(str) ...???...
const char *string = P_STRING_CONV("some string");
struct
{
char str[30];
...
}some_struct = {.str = P_STRING_CONV("some_other_string")};
我已经尝试过这样的事情:(strlen的参数可以被删除,但我需要一个定义的大小)
#define DEFINE_PASCAL_STRING(var, str, strlen) struct {uint8_t len; char content[strlen-1];} (var) = {sizeof(str)-1, (str)}
工作正常,但不能用于初始化结构中的元素。而对于const char数组,我需要将其转换为其他变量。
任何好主意?
你可以在宏观分为两个:
#define PASCAL_STRING_TYPE(size) struct { unsigned char len; char content[(size) - 1]; }
#define PASCAL_STRING_INIT(str) { .len = sizeof(str) - 1, .content = (str) }
然后使用它像这样:
static const PASCAL_STRING_TYPE(100) foo = PASCAL_STRING_INIT("foo");
struct bar {
int answer;
PASCAL_STRING_TYPE(100) question;
};
static const struct bar quux = {
.answer = 42,
.question = PASCAL_STRING_INIT("The Answer")
};
(未测试)。
好主意。 但是我不能''extern PASCAL_STRING_TYPE(30)some_string;'因为编译器认为它是不同的声明,它认为是不兼容的。 但是对于静态功能,它可以按我的需要工作。 – Tajen
是的,但你可以'typedef PASCAL_STRING_TYPE(30)pstr30;'和'extern pstr30 some_string;'。 –
将字符串转换为帕斯卡字符串类型
要转换字符串文字,_Generic
和复合文字将接近OP目标。
为了更好的解决方案,更多细节和示例用例将有助于说明OP的目标。
#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;
}
输出
L:0 ""
L:1 "A"
L:2 "AB"
L:3 "ABC"
@Jonathan Leffler建议创建类似于Pascal的串还包含一个终止空字符。要使用上述代码,请将sizeof(X)-1
简单更改为sizeof(X)
。然后通过访问pascal_like_string + 1
,代码有一个指向有效C字符串的指针。
数组类型转换为指针
sizeof(X)-!!sizeof(X)
产生大小字符串的文字,不计算其\ 0。至少1.
struct {char len; char s[sizeof(X)-!!sizeof(X)]; }
是一个正确大小的pascal状结构。
(struct {char len; char s[sizeof(X)-!!sizeof(X)]; }){ (char)(sizeof(X)-1), (X) }
是复合文字。
下面将一个C 串转换为像串帕斯卡。请注意,作为类似pascal的字符串,没有'\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;
}
要在C中有用,即使是一个Pascal类型的字符串也需要存储一个空终止符,以便它可以传递给期望C字符串的函数,而不是Pascal字符串。例如系统调用('open()'等)需要它。 C库的大部分需要C字符串。不得不复制Pascal字符串以创建C字符串将是不必要的繁重工作。您不必考虑长度字节中的空值(它只是在那里;长度只是记录空字符的数量)。你(IMNSHO)必须添加它。了解长度具有重要的优势。 –
@JonathanLeffler够了。 OP做了评论“我需要与一个使用Pascal类似字符串的系统进行通信”,所以这段代码会这样做。我怀疑OP需要一些p-string常量。如果OP请求一个像Pascal类型的字符串和C字符串一样工作的对象,那么对于更灵活的对象,您的想法肯定是有价值的。请注意,从C字符串到普通pascal_and_C类似字符串的转换会引发额外的内存管理问题,而只需要纯粹的C/Pascal转换。 – chux
我不明白'sizeof(X) - !! sizeof(X)'的意思。如果'X'是一个字符串文字,'sizeof(X)'将至少为1(即使'X'为'“”'),所以'!! sizeof(X)'将永远是1.但是,如果'X'是''“',那么该数组将被声明为's [0]',这是无效的(尽管gcc接受它)。 – rici
1.你为什么要这样做?我认为我并不真正了解你实际想要达到什么目标。 –
主要的问题是,你似乎认为类似Pascal的字符串与C字符串(指向char的指针或char的数组)是兼容的,它实际上并不自然。使用类似Pascal的字符串会解决什么问题?你为什么要使用它们? –
至少,这些字符串应该保留一个NUL终止符,因此将它们的最大长度减少到254个字符。至少可以通过传递[address + 1]将它们用作const参数。 –