2017-08-30 159 views
0

我想要一个宏将预处理器定义的字符串转换为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数组,我需要将其转换为其他变量。

任何好主意?

+4

1.你为什么要这样做?我认为我并不真正了解你实际想要达到什么目标。 –

+1

主要的问题是,你似乎认为类似Pascal的字符串与C字符串(指向char的指针或char的数组)是兼容的,它实际上并不自然。使用类似Pascal的字符串会解决什么问题?你为什么要使用它们? –

+2

至少,这些字符串应该保留一个NUL终止符,因此将它们的最大长度减少到254个字符。至少可以通过传递[address + 1]将它们用作const参数。 –

回答

0

你可以在宏观分为两个:

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

(未测试)。

+0

好主意。 但是我不能''extern PASCAL_STRING_TYPE(30)some_string;'因为编译器认为它是不同的声明,它认为是不兼容的。 但是对于静态功能,它可以按我的需要工作。 – Tajen

+0

是的,但你可以'typedef PASCAL_STRING_TYPE(30)pstr30;'和'extern pstr30 some_string;'。 –

1

将字符串转换为帕斯卡字符串类型

要转换字符串文字,_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; 
} 
+0

要在C中有用,即使是一个Pascal类型的字符串也需要存储一个空终止符,以便它可以传递给期望C字符串的函数,而不是Pascal字符串。例如系统调用('open()'等)需要它。 C库的大部分需要C字符串。不得不复制Pascal字符串以创建C字符串将是不必要的繁重工作。您不必考虑长度字节中的空值(它只是在那里;长度只是记录空字符的数量)。你(IMNSHO)必须添加它。了解长度具有重要的优势。 –

+0

@JonathanLeffler够了。 OP做了评论“我需要与一个使用Pascal类似字符串的系统进行通信”,所以这段代码会这样做。我怀疑OP需要一些p-string常量。如果OP请求一个像Pascal类型的字符串和C字符串一样工作的对象,那么对于更灵活的对象,您的想法肯定是有价值的。请注意,从C字符串到普通pascal_and_C类似字符串的转换会引发额外的内存管理问题,而只需要纯粹的C/Pascal转换。 – chux

+0

我不明白'sizeof(X) - !! sizeof(X)'的意思。如果'X'是一个字符串文字,'sizeof(X)'将至少为1(即使'X'为'“”'),所以'!! sizeof(X)'将永远是1.但是,如果'X'是''“',那么该数组将被声明为's [0]',这是无效的(尽管gcc接受它)。 – rici