有没有办法在c?
中的字符串化之前评估表达式示例:
#define stringify(x) #x
...
const char * thestring = stringify( 10 * 50 );
问题在于我想要
const char * thestring = "500";
不:
const char * thestring = "10 * 50";
可以这样做吗?
答案 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);
为简单起见,我省略了错误控制和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”: - )