2017-08-30 23 views
0

プリプロセッサ定義の文字列をパスカル型の文字列に変換し、const char配列などを初期化するマクロを使用できるようにするためのアイデアがあります。このようなC文字列をパスカル文字列型に変換するマクロ

何かが素晴らしいことだ:

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

私はすでにこのような何か試してみました:

#define DEFINE_PASCAL_STRING(var, str, strlen) struct {uint8_t len; char content[strlen-1];} (var) = {sizeof(str)-1, (str)} 

を(STRLENパラメータを除去することができますが、私は定義されたサイズを必要としています。)

これはうまくいきますが、構造体の要素を初期化するためには使用できません。 const char配列の場合は、他の変数にキャストする必要があります。

素晴らしいアイデアですか?

+4

1.なぜあなたはこれをやろうとしていますか?私はあなたが実際に達成したいことが何であるかを本当に理解していないと思います。 –

+1

大きな問題は、Pascalのような文字列がCの文字列( 'char'へのポインタ、' char'の配列)と互換性があると考えるように思えます。パスカルのような文字列を使って問題が解決するのは何ですか?なぜあなたはそれらを使いたいのですか? –

+2

少なくとも、文字列はNULターミネータを保持する必要があります。したがって、最大長を254文字に減らす必要があります。少なくともあなたはconst引数として[address + 1]を渡すことでそれらを使うことができます。 –

答えて

0

次の2つにマクロを分割することができます:

#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

Trueですが、 '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作成パスカルのような文字列も終了ヌル文字が含まれていることをお勧めします。上記のコードでは、sizeof(X)-1sizeof(X)に変更するだけです。そしてpascal_like_string + 1にアクセスすると、コードには有効なC文字列へのポインタがあります。


​​は

sizeof(X)-!!sizeof(X)

が\ 0をカウントしない、リテラル文字列のサイズを生成するポインタに配列型変換します。少なくとも1。

struct {char len; char s[sizeof(X)-!!sizeof(X)]; }正しいサイズのパスカルのような構造です。

(struct {char len; char s[sizeof(X)-!!sizeof(X)]; }){ (char)(sizeof(X)-1), (X) }は、化合物記号である。


以下では、文字列のようにパスカルにC 文字列を変換します。パスカルのような文字列としては、'\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言語で有用であるためには、パスカル型文字列でもNULL終止符を格納する必要があるため、パスカル文字列ではなくC文字列を使用する関数に渡すことができます。システムコールのようなもの、例えば( 'open()'など)はそれを要求します。 Cライブラリの大部分はC文字列を必要とします。 Pascal文字列をコピーしてC文字列を作成することは、不必要に大変な作業になります。長さバイトのヌルを考慮する必要はありません(単純にそこにあり、長さは単にヌルまでの文字数を記録します)。あなたは(IMNSHO)それを追加する必要があります。長さを知ることは重要な利点があります。 –

+0

@JonathanLeffler十分に公正。 OPは "私はパスカルのような文字列を使用するシステムと通信する必要がある"というコメントをしました。私はOPにいくつかのp文字列定数が必要だと思う。 OPがPascalのような文字列とCの文字列の両方のように機能するオブジェクトを要求していたなら、あなたのアイデアはより柔軟なオブジェクトで確かに価値があります。 Cの文字列から一般的なpascal_and_Cのような文字列への変換では、純粋なCからP/Pへの変換だけでは不要な追加のメモリ管理の問題が発生することに注意してください。 – chux

+0

私は 'sizeof(X) - !! sizeof(X)'のポイントを得られません。 'X 'が文字列リテラルの場合、' sizeof(X) 'は少なくとも1(' X'が '' '' ')であっても1になりますので、' !! sizeof(X) 'は常に1になります。 'X'が' '' 'の場合、配列は' s [0] 'として宣言されますが、gccはそれを受け入れます。 – rici

関連する問題