循环遍历并将数据分配给结构成员的宏错误地将结构成员识别为指针 [英] Macro to cycle through and allocate data to members of structs incorrectly recognises struct member as pointer

查看:59
本文介绍了循环遍历并将数据分配给结构成员的宏错误地将结构成员识别为指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是atoi正在将字符串的十六进制内存地址转换为十进制,而不是字符串中包含的内容.它在宏过程中正在执行此操作.当宏定义将其构造为int时,为什么将struct-> member解释为指针?伪代码如下:

My problem is that atoi is converting a string's hexadecimal memory address to decimal, instead of what's contained within the string. It is doing this during a macro. Why is it interpreting struct->member as a pointer, when the macro definition makes it an int? Pseudocode below:

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

该程序此部分的目的是从.csv文件中检索包含有关structs属性的信息的数据.我可以输入一个"id",并将每个单元格字符串存储到字符串数组(csvRowSplit)中.

The aim of this section of the program is to retrieve data from a .csv file containing information about a structs attributes. I can take in an "id" and store each cells string into an array of strings (csvRowSplit).

但是,然后我想将数组的内容传输到包含不同数据类型的结构(我想用来检索保存的玩家属性,攻击方法,商店物品等的方法).进行硬编码很容易:

However, I then want to transfer the contents of the array to a structure that contains different data types (a method that I want to use to retrieve players saved attributes, attack methods, shop items etc.). It's easy to hard code:

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

但是,这会混杂更多的struct成员,并且不太灵活或不可复制.

However this clutters with more struct members and is not very flexible or reproducible.

我已经定义了一个宏来循环遍历结构的各个元素,并将csvSplitRow []与变量配对,并在需要时与atoi进行转换.

I have defined a macro to cycle through the elements of a structure, and pair up the csvSplitRow[] to the variables, converting if required with 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导致将十六进制内存地址转换为整数,而不是其指向的字符串.

The assignment directly to the string members work (ie. no conversion), but atoi results in a conversion of the hexadecimal memory address to an integer, instead of the string it's pointing to.

// 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的已解析行匹配时,都需要硬代码.请帮忙!

I don't know what I can do now, other than hard code each time I want to match up a parsed line of csv with a structure. Please help!

我收到-Werror的编译时错误:

I get a compile time error with -Werror:

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

错误在update_opp函数的宏内.但是,我知道它不是指针,因为我早先将其定义为int吗?那么为什么不认识到这一点呢?而且我无法投放,该怎么办?

Error is within the macro of the update_opp function. However, I know it's not a pointer because I defined it to be an int earlier? So why isn't it recognizing that? and I can't cast it, so what can I do?

推荐答案

您的问题在以下代码中:

Your problem is in this code:

#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),您将得到:

For any given attribute name (att say), you get:

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

除了全部在一行上.但是,关键是您在每次调用中都将int(从atoi())分配给字符串,或者在每个调用中将字符串分配给int,而这两者之一是错误的.代码必须先正确才可以优化.

Except that it is all on one line. But, the key point is that you either assign an int (from atoi()) to a string or you assign a string to an int in every invocation, and one of those two is wrong. The code has to be correct before it is optimized.

如何解决?那很棘手.我想我可能会使用这样的东西:

How to fix? That's tricky. I think I'd probably use something like this:

#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
}

这会在非常严格的编译器标志下进行编译,而不会发出警告:

This compiles without warnings under very stringent compiler flags:

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

需要执行其他操作时,可以重新定义CVT_INTCVT_STR宏.

The CVT_INT and CVT_STR macros could be redefined when required to do other things.

该代码的替代版本更广泛地利用了CVT_INTCVT_STR(重命名为X_INTX_STR):

An alternative version of the code exploits CVT_INT and CVT_STR (renamed to X_INT and X_STR) more extensively:

#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
}

我不是100%相信由于多次#define#undef操作会更好,但是在某些方面它几乎是最小的(不需要"%d" vs "%s"字段,例如-至少不在显示的代码中).

I'm not 100% convinced this is better because of the multiple #define and #undef operations, but it is more nearly minimal in some respects (it doesn't need the "%d" vs "%s" fields, for example — at least, not in the code shown).

这篇关于循环遍历并将数据分配给结构成员的宏错误地将结构成员识别为指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆