2017-08-30 238 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