如何在C中字符串化表达式

时间:2009-08-13 22:34:28

标签: c

有没有办法在c?

中的字符串化之前评估表达式

示例:

#define stringify(x)  #x
...
const char * thestring = stringify( 10 * 50 );

问题在于我想要

const char * thestring = "500";

const char * thestring = "10 * 50";

可以这样做吗?

7 个答案:

答案 0 :(得分:10)

C预处理器无法做到这一点,因此请改用snprintf

char *stringify(int n) {
   char *res = malloc(12);
   snprintf(res, 12, "%d", n);
   return res;
}

用法

const char *thestring = stringify(10 * 50);

NB

为简单起见,我省略了错误控制和free

答案 1 :(得分:5)

您可能不喜欢表达式的格式, 可能,但是以一种非常折衷的方式 - 你' d需要创建一个由预处理器“运行”的独立功能语言。证明:

$ cvs -d:pserver:anonymous@chaos-pp.cvs.sourceforge.net:/cvsroot/chaos-pp login 
$ cvs -z3 -d:pserver:anonymous@chaos-pp.cvs.sourceforge.net:/cvsroot/chaos-pp co -P chaos-pp
$ cvs -z3 -d:pserver:anonymous@chaos-pp.cvs.sourceforge.net:/cvsroot/chaos-pp co -P order-pp
$ cd order-pp/example
$ grep -A 6 'int main' fibonacci.c
int main(void) {
   printf
     ("The 500th Fibonacci number is "
      ORDER_PP(8stringize(8to_lit(8fib(8nat(5,0,0)))))
      ".\n");
   return 0;
}
$ cpp -I../inc fibonacci.c 2>/dev/null | grep -A 6 'int main' 
int main(void) {
   printf
     ("The 500th Fibonacci number is "
      "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125"
      ".\n");
   return 0;
}

在这个例子中,我们使用新制作的预处理器运行的纯函数式语言来计算第500个Fibonacci数,然后将其字符串化以提供给C编译器。

当然,我非常怀疑这是你在实践中曾经使用过的东西,而且它对预处理器的滥用非常紧张,但我认为这是一个非常发人深省的黑客攻击。 (是的,没有像这样的奇特的理论曲折,这是不可能的。)

答案 2 :(得分:4)

我会猜测你在脚本语言方面比在C语言方面有更多经验。

使用纯编译语言(如C:Preproccesing,Compiling,Linking和Running

)需要注意多个阶段。

首先运行预处理器。这就是宏扩展的地方。此时,其内容为“10 * 50”。没什么可做的。

宏预处理器完成后,编译器将程序转换为目标文件

编译器在每个源文件上完成后,链接器会介入并将它们全部打包在一起。

最后,当您的用户准备好后,他们执行您的程序。语义上,这是计算10 * 50的时间。 (实际上,大多数编译器都会认识到这将始终是相同的值,并将其替换为500,但这是一个实现细节。)

脚本语言喜欢模糊所有这些行,所以我可以看到某人习惯其中之一的地方可能会混淆。

答案 3 :(得分:1)

预编译器宏在编译器之前运行。根据定义,它不可能完全按照你正在做的事情去做。

要在运行时将数字转换为字符串,请调用itoa函数,如下所示:

char thestring[8];

itoa(10 * 50, thestring, 10);

请注意,此代码将thestring声明为数组,而不是指针。有关更多信息,请阅读C中的内存管理。

答案 4 :(得分:0)

您需要解释字符串。 C本身并不这样做,查找一个可以为你做的文库。

http://expreval.sourceforge.net/ http://www.codeproject.com/KB/library/expreval.aspx

还有其他人,只是搜索谷歌。

答案 5 :(得分:-1)

你可以编写一个脚本(perl?)来用作预处理器,它可以识别要评估的字符串,对它们进行评估,然后在“已评估”文件中调用真正的cpp。

也许它可行。

答案 6 :(得分:-2)

正如其他回复所说,使用C预处理器无法做到这一点。这是C语言解决的C的许多缺点之一,这是可以使用模板元编程以非常优雅的方式完成的事情。

在编译时计算算术表达式:

#include <boost/mpl/arithmetic.hpp>
namespace mpl = boost::mpl;
int main(int argc, char *argv[]) {
  const int n = mpl::multiplies<mpl::int_<10>, mpl::int_<50> >::value;
  return 0;
}

这是我在boost邮件列表档案中找到的string formatting metafunction。此版本将int(如上面计算的那个)转换为您选择的基础中的字符串:

#include <boost/mpl/string.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/push_back.hpp>
namespace mpl = boost::mpl;
struct itoa_ct
{
  // radix for _itoa() goes up to 36, but only bother with 16 here
  typedef mpl::vector_c<char
    ,'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
    > radix_t;
  template <int Radix, unsigned int Quotient>
    struct radix_convert
    {
      typedef typename mpl::push_back<
        typename radix_convert<Radix, Quotient / Radix>::type
        , mpl::char_<mpl::at_c<radix_t, Quotient % Radix>::type::value>
        >::type type;
    };
  template <int Radix>
    struct radix_convert<Radix, 0>
    {
      typedef mpl::string<> type;
    };
  template <int I, int Radix = 10>
    struct apply
    {
      // All bases != 10 consider I as unsigned
      typedef typename radix_convert<
        Radix, static_cast<unsigned int>((Radix == 10 && I < 0) ? -I : I)
        >::type converted_t;
      // Prefix with '-' if negative and base 10
      typedef typename mpl::if_<
        mpl::bool_<(Radix == 10 && I < 0)>
        , mpl::push_front<converted_t, mpl::char_<'-'> >
        , mpl::identity<converted_t>
        >::type::type type;
    };
};

将两者放在一起表达式为:

const char *thestring = mpl::c_str<itoa_ct::apply<mpl::multiplies<mpl::int_<10>, mpl::int_<50> >::value>::type>::value;

...这一切在编译时变成了一个常量字符串“500”: - )