是否有任何 C 函数可以计算标准库中定义的字符串表达式?

问题描述 投票:0回答:4

我正在寻找一个可以将字符串表达式计算为整数的函数,例如 f.e.:

10/2+4*3-(12+5); //Equals 0

转换为

int
类型的对象,其值为
0

复杂操作的功能会更好,即使这不是当时的需要:

2^(1/2)-99

标准 C 库(C89、C90,如果已编译)中是否定义了此类定义?

有没有非标准库有这样的功能?

表达式支持的字符越多越好。

但即使是像 +、-、*、/、() 这样的基本操作也可以。

c string type-conversion integer expression
4个回答
4
投票

标准 C 库(C89、C90,如果已编译)中是否定义了此类定义?

不,即使在更新的 C11 或 C18 标准库中也没有。

有没有非标准库有这样的功能?

我也找不到。您必须编写自己的函数来完成此任务。

也许在第一步扫描字符串并将其中的每个值存储到单独的字符串中。

正如我在评论中已经建议的那样,

strtol
用于将字符串中的像
11
这样的整数值转换为
int
类型的值。您可能需要利用它。库中还有一个
atoi
函数,可将字符串内的整数值转换为
int
,但该函数更容易出错,不应使用。

算术运算符也应存储在单独的字符串中,但稍后由自制例程进行评估。

但是可以在这里找到很好的示例和建议,其中用户被问到类似(如果不相同)的问题:

C:将数学表达式字符串转换为 int 并给出结果


3
投票

标准 C 库中没有计算算术表达式的函数。这是一个针对

evald
结果的
double
函数的快速而肮脏的实现。它支持 5 种经典二元运算
+
-
*
/
%
以及
^
求幂,处理任何深度的括号,但需要更多的一元
+
 工作-

很容易转换为纯整数算术。

这是代码:

#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

double evald(const char *s, char **endp) {
    struct operand {
        double val;
        int op, prec;
    } stack[4], *sp, x;
    char *p;

    for (sp = stack;;) {
        if (*s == '(') {
            x.val = evald(s + 1, &p);
            s = p;
            if (*s == ')')
                s++;
        } else {
            x.val = strtod(s, &p);
            s = p;
        }
        while (isspace((unsigned char)*s))
            s++;
        switch (x.op = *s++) {
        case '^': x.prec = 3; break;
        case '*':
        case '/':
        case '%': x.prec = 2; break;
        case '+':
        case '-': x.prec = 1; break;
        default:  x.prec = 0; x.op = 0; s--; break;
        }
        while (sp > stack && x.prec <= sp[-1].prec) {
            switch ((--sp)->op) {
            case '^': x.val = pow(sp->val, x.val); break;
            case '*': x.val = sp->val * x.val; break;
            case '/': x.val = sp->val / x.val; break;
            case '%': x.val = fmod(sp->val, x.val); break;
            case '+': x.val = sp->val + x.val; break;
            case '-': x.val = sp->val - x.val; break;
            }
        }
        if (!x.op) break;
        *sp++ = x;
    }
    if (endp) *endp = (char *)s;
    return x.val;
}

int main(int argc, char *argv[]) {
    if (argc > 1) {
        for (int i = 1; i < argc; i++) {
            printf("%s -> %.17g\n", argv[i], evald(argv[i], NULL));
        }
    } else {
        char buf[100];
        for (;;) {
            printf("eval> ");
            fflush(stdout);
            if (!fgets(buf, sizeof buf, stdin) || (buf[0] == 'q' && buf[1] == '\n'))
                break;
            printf(" -> %.17g\n", evald(buf, NULL));
        }
    }
    return 0;
}

1
投票

有没有非标准库有这样的功能?

GNU bison就有这样的例子。

bison
是一个解析器生成器,并且是一个生成C文件的免费软件工具。

您还可以在您的应用程序中使用并嵌入 Lua。它是开源,所以你应该研究它的源代码。 Lua 大部分是用标准 C99 编码的。

您可以编写自己的递归下降解析器,非常简单。

您可以考虑在您的应用程序中嵌入 GNU GuilePython

当然,您应该使用比过时的 MS-DOS(或其 FreeDOS 替代品)更好的操作系统。我想到了 Debian

你可以使用tinycc,它有一个与你的需求类似的库(

libtcc
),你可以研究它的源代码。

你需要阅读有关解析和编译的教科书。我想到了龙书。或者至少阅读有关 parsinglexing 的维基百科页面。


0
投票

以下是我向 RobertS 的解析器添加一元运算符的方法。在第一次进入或递归解析循环之前的 ()' 内部内容时,您将 0 与运算符一起以最高优先级压入堆栈。然后它可以处理:-(2-5)^2,即-(-3),然后对9进行平方,甚至-((2-5)**2)并得到-9的值。每次堆栈推送都会将一个值/运算符(按该顺序)放入堆栈中,并将下一对与堆栈顶部进行比较。 (我花了一段时间掌握这个算法的窍门)。

此外,您还可以通过将函数简单地视为 () 来添加函数,一旦递归求值,就会在被推入堆栈之前通过函数运行。

  if (c  == '+' || c == '-') { // check for initial uniary+ or - 
        x.val = 0.0;
        x.op  = c;
        x.prec = 3;  // give it highest priority
        *sp++ = x;  // pretend we started with a 0, so it's 0+... or 0-...
        s++;
    }
© www.soinside.com 2019 - 2024. All rights reserved.