Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将空指针(结构的一部分)强制转换为另一个指针数据类型_C_Parsing_Lisp - Fatal编程技术网

C 将空指针(结构的一部分)强制转换为另一个指针数据类型

C 将空指针(结构的一部分)强制转换为另一个指针数据类型,c,parsing,lisp,C,Parsing,Lisp,我试图自己找出如何解析C中的S表达式,以便为我自己的初级Lisp(作为学习练习编写,而不是用于生产)存储数据和代码 在解释我的代码和我的推理之前,我应该解释一下,我所知道的关于S表达式的所有信息都是Wikipedia文章中关于它的介绍部分,偶尔也会浏览一下常见的Lisp代码,所以我的结构和变量的命名可能有点不对劲 我的实现语言是C,在定义任何函数之前,我创建了以下结构: typedef enum { string, letter, integer, } atom_type

我试图自己找出如何解析C中的S表达式,以便为我自己的初级Lisp(作为学习练习编写,而不是用于生产)存储数据和代码

在解释我的代码和我的推理之前,我应该解释一下,我所知道的关于S表达式的所有信息都是Wikipedia文章中关于它的介绍部分,偶尔也会浏览一下常见的Lisp代码,所以我的结构和变量的命名可能有点不对劲

我的实现语言是C,在定义任何函数之前,我创建了以下结构:

typedef enum {
    string,
    letter,
    integer,
} atom_type;

typedef struct {
    void* blob;
    atom_type type;
} atom;

typedef struct expr {
    atom* current;
    struct expr* next;
} expr;
每个原子都存储在一个struct
atom
,其中包含一个enum实例(我不确定这个术语是否正确)和一个指向要存储的数据的空指针。每个S表达式“节点”由一个指向原子的指针和一个指向下一个S表达式节点的指针组成

我编写了一个基本函数,它接受字符串并将其解析为原子,如下所示:

atom* parse_term(char* str) {
    size_t len = strlen(str);
    atom* current = malloc(sizeof(atom));
    
    if(str[0] == '\'') {
        current->blob = (char*) &str[1];
        current->type = letter;
    } else if(str[0] == '\"') {
        char temp[256];
        int pos = 1;

        while(str[pos] != '\"') {
            temp[pos] = str[pos];
            pos++;
        }
        current->blob = malloc(256 * sizeof(char));
        current->blob = (char*) &temp;
        current->type = string;
    } else if(isdigit(str[0])){
        char temp[256];
        int pos = 0;

        while(str[pos] != ' ') {
            temp[pos] = str[pos];
            pos++;
        }
        int tmp = atoi(temp);
        current->blob = (int*) &tmp;
        current->type = integer;
    }
    return current;
}
该功能似乎工作正常;至少,当我打印出数据类型时,它会正确地显示它。但除此之外,我不知道如何打印出实际的“blob”:我尝试使用%p格式代码以及switch语句:

void print_atom(atom* current) {
    switch(current->type) {
        case string:
            printf("atom%s\ttype:%d", current->blob, current->type);
        case letter:
            printf("atom%c\ttype:%d", current->blob, current->type);
        case integer:
            printf("atom%c\ttype:%d", current->blob, current->type);
    }
}
但这不起作用。在字符串的情况下,它返回乱码文本,而在其他情况下,它只是不打印原子信息应该存在的任何内容


我想这是我在结构中使用void*的结果;我该怎么补救呢?我认为我确实正确地进行了强制转换(尽管我很可能是错的,请告诉我),我唯一能想到的另一个选择是在“atom”结构中为每个受支持的数据类型存储一个硬编码变量,但这似乎浪费了资源。

不要使用
void*
。使用
接头
。这就是
union
s的作用

在这个例子中,我使用了一个“匿名联合”,这意味着我可以引用它的字段,就好像它们直接在Atom结构中一样。(我根据自己的偏见更改了名称的拼写,因此类型大写,常量为ALLCAPS。我还将Atom的typedef和struct声明分开,以防Atom是自引用的

typedef枚举{
一串
信,
整数
}原子型;
类型定义结构原子;
结构原子{
联合{
char*str;
煤焦;
int-num;
};
原子型;
};
无效打印\u原子(原子*当前){
开关(当前->类型){
大小写字符串:
printf(“原子%s\t类型:%d”,当前->str,当前->类型);
案例信:
printf(“原子%c\t类型:%d”,当前->let,当前->tyoe);
大小写整数:
printf(“原子%d\t类型:%d”,当前->数量,当前->类型);
}
}
正如有人在评论中所说,Lisp对象实际上不是这样的。通常的实现是将cons单元格和atoms组合起来,类似这样(而不是
AtomType
)。您还需要将
CELL
添加到枚举中

typedef结构单元;
结构单元{
联合{
char*str;
煤焦;
int-num;
结构{
Cell*hd;//历史名称:car
Cell*tl;//历史名称:cdr
};
};
细胞型;
};
这里有一个匿名联合中的匿名结构。一些人说这令人困惑。其他人(不管怎样,我)说它的语法噪音更小。请使用您自己的判断

Cell
的定义中使用
Cell*
typedef struct Cell Cell
的动机

你可以玩不完全便携但通常是ok的游戏来减少
单元的内存消耗,而大多数实际实现都是这样。我没有,因为这是一种学习体验



还要注意的是,真正的Lisp(和许多玩具Lisp)有效地避免了大多数解析任务;该语言包括字符宏,可以有效地执行所需的解析(这并不多);在大多数情况下,它们可以在Lisp本身中实现(尽管您需要某种引导方式).

基本的Lisp数据类型是cons单元格,用于表示列表。它包含两个对称字段:car和cdr,这两个字段都指向S表达式。cons单元格用于表示列表,但最基本的是点对。S表达式可以是cons单元格、符号、字符串、数字等。
当前->blob=malloc(256*sizeof(char));当前->blob=(char*)&temp;
=即时内存泄漏,最终在
temp
之后UB不再有效。事实上,所有存储自动本地变量(temp,tmp)地址的代码行,然后在对象生命周期之外使用这些地址是未定义行为的秘诀。请看更多详细信息/hintsBuildYourOwnLisp最初让我对Lisp感兴趣-我故意选择不遵循该教程,因为它依赖于解析器库,而解析器正是我期待编写的部分。