我的问题是atoi正在将字符串的十六进制内存地址转换为十进制,而不是字符串中包含的内容。它是在宏中执行此操作。当宏定义使其成为int时,为什么将struct->成员解释为指针?下面的伪代码:
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导致将十六进制内存地址转换为整数,而不是它指向的字符串。
// 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?那为什么不承认呢?我不能施展它,所以我该怎么办?
答案 0 :(得分: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++;
除了它全部在一条线上。但是,关键的一点是,您要么将int
(从atoi()
)分配给字符串,要么在每次调用时将字符串分配给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_INT
和CVT_STR
(重命名为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
和#undef
操作,我不是100%确信这更好,但在某些方面它更接近最小(它不需要{{1}例如,vs "%d"
字段 - 至少不在显示的代码中。)