3

私の問題は、文字列に含まれるものではなく、atoi が文字列の 16 進数のメモリ アドレスを 10 進数に変換していることです。マクロ中にこれを行っています。マクロ定義で int になっているのに、struct->member をポインターとして解釈するのはなぜですか? 以下の疑似コード:

if (struct.member == int)? struct.member = atoi(data) : struct.member = data;

プログラムのこのセクションの目的は、構造体の属性に関する情報を含む .csv ファイルからデータを取得することです。「id」を取得して、各セルの文字列を文字列の配列 (csvRowSplit) に格納できます。

ただし、配列の内容を、さまざまなデータ型 (プレーヤーの保存された属性、攻撃方法、ショップ アイテムなどを取得するために使用する方法) を含む構造体に転送したいと考えています。ハードコーディングするのは簡単です:

opponent->att = atoi(csvSplitRow[0]);
opponent->= atoi(csvSplitRow[1]);
opponent->hitpoints = atoi(csvSplitRow[2]);
opponent->description = csvSplitRow[3]);

ただし、これはより多くの構造体メンバーで混乱し、柔軟性や再現性があまりありません。

構造体の要素を循環するマクロを定義し、csvSplitRow[] を変数にペアにして、必要に応じて atoi で変換します。

#define X_FIELDS \
    X(char*, description, "%s") \
    X(int, xpreward, "%d") \
    X(int, att, "%d") \
    /* ... */
    X(int, crit, "%d")

typedef struct
{
    #define X(type, name, format) type name;
        X_FIELDS
    #undef
}

void update_opp(char** csvSplitRow, opp* opponent)
{
    int i = 0;
    #define X(type, name, format) \
        if (strcmp(format, "%d") == 0) \          // if an int, convert it
            opponent->name = atoi(csvSplitRow[i]); \
        else \                                    // otherwise put it straight in
            opponent->name = csvSplitRow[i]; \
        i++;
    X_FIELDS
    #undef X
}

文字列メンバーへの直接代入は機能しますが (つまり、変換は行われません)、atoi を使用すると、16 進数のメモリ アドレスが、指している文字列ではなく整数に変換されます。

// before conversion
csvRowSplit[1] == 0x501150 "20"

// practice
atoi(csvRowSplit[1]) == 20

// after conversion and storing in struct int member
opponent->xpreward = atoi(csvSplitRow[1]);
opponent->xpreward == 5247312           // the decimal equivalent of 0x501150

解析された csv の行を構造と照合するたびにハードコードを実行する以外に、今何ができるかわかりません。助けてください!

編集: -Werror でコンパイル時エラーが発生します:

error: assignment makes integer from pointer without a cast [-Werror]

update_opp 関数のマクロ内にエラーがあります。ただし、以前に int であると定義したため、ポインターではないことはわかっていますか? では、なぜそれを認識しないのでしょうか。キャストできないので、どうすればいいですか?

4

1 に答える 1

1

あなたの問題はこのコードにあります:

#define X(type, name, format) \
    if (strcmp(format, "%d") == 0) \          // if an int, convert it
        opponent->name = atoi(csvSplitRow[i]); \
    else \                                    // otherwise put it straight in
        opponent->name = csvSplitRow[i]; \
    i++;

任意の属性名 (attたとえば) に対して、次のようになります。

    if (strcmp("%d", "%d") == 0)
        opponent->att = atoi(csvSplitRow[i]);
    else
        opponent->att = csvSplitRow[i];
    i++;

それがすべて1行にあることを除いて。ただし、重要な点は、すべての呼び出しでint(from atoi()) を文字列に割り当てるか、文字列を anに割り当てることであり、これら 2 つのうちの 1 つが間違っています。int最適化する前に、コードを正しくする必要があります。

直し方?それはトリッキーです。私はおそらく次のようなものを使用すると思います:

#include <stdlib.h>

#define CVT_INT(str)    atoi(str)
#define CVT_STR(str)    str

#define X_FIELDS \
    X(char*, description, "%s", CVT_STR) \
    X(int, xpreward, "%d", CVT_INT) \
    X(int, att, "%d", CVT_INT) \
    /* ... */ \
    X(int, crit, "%d", CVT_INT)

typedef struct opp
{
#define X(type, name, format, converter) type name;
    X_FIELDS
#undef X
} opp;

extern void update_opp(char** csvSplitRow, opp* opponent);

void update_opp(char** csvSplitRow, opp* opponent)
{
    int i = 0;

#define X(type, name, format, converter) \
    opponent->name = converter(csvSplitRow[i++]);

    X_FIELDS

#undef X
}

これは、非常に厳しいコンパイラ フラグの下で警告なしにコンパイルされます。

gcc -pedantic -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
    -Wold-style-definition -c xm.c

CVT_INTおよびマクロはCVT_STR、他のことを行う必要がある場合に再定義できます。


コードの別のバージョンでは、CVT_INTand CVT_STR(名前が and に変更されましたX_INT)X_STRがより広範に利用されています。

#include <stdlib.h>

#define X_FIELDS \
    X(X_STR, description) \
    X(X_INT, xpreward) \
    X(X_INT, att) \
    /* ... */ \
    X(X_INT, crit)

typedef struct opp
{
#define X_INT char *
#define X_STR int
#define X(code, name) code name;
    X_FIELDS
#undef X
#undef X_INT
#undef X_STR
} opp;

extern void update_opp(char** csvSplitRow, opp* opponent);

void update_opp(char** csvSplitRow, opp* opponent)
{
    int i = 0;

#define X_INT(str)    atoi(str)
#define X_STR(str)    str
#define X(converter, name) \
    opponent->name =  converter(csvSplitRow[i++]);

    X_FIELDS

#undef X
#undef X_INT
#undef X_STR
}

#define複数のand操作があるため、これが優れていると 100% 確信しているわけではありませんが、いくつかの点でより最小限に近いものになっています (たとえば、 vsフィールド#undefは必要ありません— 少なくとも、示されているコードでは必要ありません)。"%d""%s"

于 2013-04-13T03:49:56.110 に答える