C/C++图形图像的世界

图形与游戏编程

常用链接

统计

积分与排名

Blog

最新评论

2012年1月16日 #

C/C++宏的奇技淫巧

来源:http://blog.misakamm.org/p/209
宏的主要作用就是简化代码编写,简化一些需要重复编码的地方,以得到看起来更优雅的代码。但宏要用得好并不容易,用的不好很容易引发灾难性的后果。本文会介绍宏比较偏门但又很实用的技巧。
首先就是最常用的技巧(http://blog.misakamm.org/p/209):
#define MACROCAT( x, y ) MACROCAT1 ( x, y )
#define MACROCAT1( x, y ) x##y
#define TOSTRING( s ) #s
MACROCAT把x和y展开后连結,而TOSTRING把s转化为字符串,比如可以printf(TOSTRING(%s), TOSTRING(abcdefg));
然后,因为宏不能递归,但可以做递归模拟,我们可以这样玩。比如要生成n位的二进制数并且从小到大构成的字符串(用到前面的宏):
#define BIN_0(arg) TOSTRING ( arg )
#define BIN_1(arg) BIN_0(MACROCAT(arg, 0)) "," BIN_0(MACROCAT(arg, 1))
#define BIN_2(arg) BIN_1(MACROCAT(arg, 0)) "," BIN_1(MACROCAT(arg, 1))
#define BIN_3(arg) BIN_2(MACROCAT(arg, 0)) "," BIN_2(MACROCAT(arg, 1))
#define BIN_4(arg) BIN_3(MACROCAT(arg, 0)) "," BIN_3(MACROCAT(arg, 1))
int main()
{
puts(BIN_4());
return 0;
}

这里要注意的是,比如BIN_2(),实际上展开的结果是
"0" "0" "," "0" "1" "," "1" "0" "," "1" "1"
不过c/c++规定这样连写的字符串,编译时就会合并成一个,于是就能用puts直接完整输出结果了
如果你想得到更多的位,很简单,只要你不介意,上面的宏复制并改改数字就可以了
不过,这样一改要改若干个数字,比较麻烦,能不能让它工作得更好?比如只要改宏名?
这个时候,就要用更富有技巧性的一招了:让每个宏多一个参数n,然后前面的BIN_x使用MACROCAT把它与数字连结起来,不就可以了么?
想法不错,不过问题是宏本身没有做减法的能力,能做的仅仅是替换。减1应该怎么实现呢?
其实不难,见以下定义:
#define DECVAL_1 0
#define DECVAL_2 1
#define DECVAL_3 2
#define DECVAL_4 3
#define DECVAL_5 4
#define DECVAL_6 5
#define DECVAL_7 6
#define DECVAL_8 7
#define DECVAL_9 8
#define DECVAL( n ) DECVAL_##n
好了,有了这个利器,我们就可以对原宏改造了,先拿0号和1号宏开刀:
#define BIN_0(n, arg) TOSTRING ( arg )
#define BIN_1(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 0)) \
"," MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
看得懂替换了一些什么吗?这样,后面的2,3,4,5号,只要复制一下1号的定义,改一改宏名就解决问题了
思考题:
这里生成的二进制结果是带前导0的,如何改写能使生成的结果不带前导0?
source: http://blog.misakamm.org/p/209

使用此法可以“递归”式生成很多类似代码,同时这个技巧也非常的实用,但递归构造并不容易,需要编写的人仔细想清楚,否则很容易出错,特别要注意宏展开的时机,一般不直接使用MACROCAT1宏,因为那个很可能不是你想要的结果
之后,到C99标准出台后(也就是说,下文内容与bc3/tc/vc6不兼容),宏里面多了一个狠角色:可变参数个数宏
比如可以 #define PRINTF(...) fprintf(stdout, __VA_ARGS__)
其中__VA_ARGS__代表了‘...’部分的全部参数,这样可以轻松的重定义库函数里不定参数的函数的输出行为,比如printf重定向到文件(虽然也可以用freopen实现,但只想说明宏也可以这样搞)
好了,下文将区分编译器来介绍,一共分为两派,vc派和gcc派(包括clang/objc),因为两者对以下代码的处理并不一致,需要使用略为不同的宏来实现,目前我也只遇到这两派。
现在的目的是这样,因为__VA_ARGS__包含了若干参数,我怎么才能知道里面参数有多少个呢?
比如写一个宏NUM_PARAMS(),里面写NUM_PARAMS(abc,a,d,e)的话,替换后得到的结果要是4,能办到吗?
 
 
 
 
 
 
 
 
 
 
广告时间:
http://blog.misakamm.org/p/209
广告过后,回来精彩的节目
 
 
 
 
 
 
 
 
 
 
首先先介绍gcc派的解决方案:
#define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16, N, ...) N
#define PP_RSEQ_N() \
16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
非常漂亮巧妙又简洁的方案,我想不用我多解释了吧?
不过,请注意,这是gcc的方案,以上代码放在vc8/vc9/vc2010等都会得不到正确的结果的,这个和vc的宏处理方式有关
接下来就是给出vc的解决方案(以下均以vc2008和vc2010为准)
#define BRACKET_L() (
#define BRACKET_R() )
#define PP_NARG(...) \
PP_NARG_ ( __VA_ARGS__, PP_RSEQ_N() )
#define PP_NARG_(...) \
PP_ARG_N BRACKET_L() __VA_ARGS__ BRACKET_R()
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16, N,...) N
#define PP_RSEQ_N() \
16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
这里很特别的一点是对部分小括号做了替换。
问题在于PP_NARG_到PP_ARG_N做参数传递的时候,如果已有显式的括号,那么不对里面的宏做展开计算参数个数,仅直接按显式的逗号个数判断出参数个数,从而导致__VA_ARGS__被当成一个参数传入。而把括号用宏替换掉后,则不出现直接的括号,就先对宏做展开,而展开后,再展开新构造出来的宏,这样才能让参数匹配上。
不过gcc里面不能这么干,gcc会把宏名展开出来后,如果发现后面的符号并不是显式的括号,则把前面的宏符号化,不再展开。这两种不同的特性让我现在还不知道怎么编写宏能让两派都能兼容,正确展开出我想要的东西。
解释了两个编译器的不同点以后,后面不再解释相同的问题,而会同时给出两份代码。
另一个类似的问题,就是既然有不定个数的参数,如果我希望对每个参数都做一些处理,那如何做呢?
举例,实现一个宏#define SPREAD(...),要把参数里的东西连结成一个字符串
之前的例子里,已经实现了把不定参数展开的手段,现在我们来尝试递归下降式展开(gcc版本):
#define SPREAD0( arg ) #arg
#define SPREAD1(arg, ...) SPREAD0(arg)
#define SPREAD2(arg, ...) SPREAD0(arg) SPREAD1(__VA_ARGS__,)
#define SPREAD3(arg, ...) SPREAD0(arg) SPREAD2(__VA_ARGS__,)
#define SPREAD4(arg, ...) SPREAD0(arg) SPREAD3(__VA_ARGS__,)
#define SPREAD5(arg, ...) SPREAD0(arg) SPREAD4(__VA_ARGS__,)
#define SPREAD6(arg, ...) SPREAD0(arg) SPREAD5(__VA_ARGS__,)
#define SPREAD7(arg, ...) SPREAD0(arg) SPREAD6(__VA_ARGS__,)
#define SPREAD8(arg, ...) SPREAD0(arg) SPREAD7(__VA_ARGS__,)
#define SPREAD9(arg, ...) SPREAD0(arg) SPREAD8(__VA_ARGS__,)
#define SPREAD(...) SPREAD9(__VA_ARGS__)
在这里,每进入一层,就从__VA_ARGS__拆解一个最前面的参数出来,把剩下的参数给下一层
这里有一个细节是__VA_ARGS__后面有一个逗号,意思就是补一个空参数,避免后面参数不足
然后就可以用puts(SPREAD(1, 2, 3, 4));来测试了
当然,还要使用前文的方式处理一下(gcc版):
#define SPREAD0( arg ) #arg
#define SPREAD1(n, arg, ...) SPREAD0(arg)
#define SPREAD2(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
#define SPREAD3(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
#define SPREAD4(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
#define SPREAD5(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
#define SPREAD6(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
#define SPREAD7(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
#define SPREAD8(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
#define SPREAD9(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) ( DECVAL(n), __VA_ARGS__, )
#define SPREAD(...) SPREAD9 ( 9, __VA_ARGS__ )
vc版:
#pragma warning(disable:4003) // 去除警告
#define SPREAD0( arg ) #arg
#define SPREAD1(n, arg, ...) SPREAD0(arg)
#define SPREAD2(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
#define SPREAD3(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
#define SPREAD4(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
#define SPREAD5(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
#define SPREAD6(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
#define SPREAD7(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
#define SPREAD8(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
#define SPREAD9(n, arg, ...) SPREAD0(arg) MACROCAT(SPREAD, DECVAL(n)) BRACKET_L() DECVAL(n), __VA_ARGS__, BRACKET_R()
#define SPREAD(...) SPREAD9 BRACKET_L() 9, __VA_ARGS__, BRACKET_R()
以上只是模糊方式展开,因为参数个数不知道,后面会遇到宏参数为空的情况,于是vc编译器给出了警告
如果把之前说的过技巧,就是分析出不定参数个数的宏,与这个结合,将产生更大的威力,我们可以实现精确展开,就是在SPREAD宏的定义里,有9的地方使用宏PP_NARG(__VA_ARGS__)替换一下,于是__VA_ARGS__后面的逗号可以去掉,也可以简化一些代码了,也能避免展开后有你所不希望的多余字符出现。
测试考题1:
定义一宏#define printf,让它能把printf(str, a, b, c);替换成std::cout<<a<<b<<c<<std::endl;
参数个数不确定,不用考虑str的内容,但假设不多于10个参数

http://blog.misakamm.org/p/209
宏的威力还不止至此,当宏与C++模板编程结合的时候,真正的可怕就来临了。。。
测试考题2:
在C++0x之前,模板还没有不定参数,于是需要多个参数的时候,不得不手工解决,或者聪明的人,使用模板来生成多参模板代码。尝试一下这么做,看看和之前的问题难度加大在哪里。比如生成一个名为sum的模板函数,能接受1 - 10个参数,返回这些参数的相加的结果

 
 
 
 
 
 
 
 
 
 
 
文章附带:
第一考题参考答案:
#define BINARY_E0(n, arg) TOSTRING ( arg )
#define BINARY_E1(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
#define BINARY_E2(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
#define BINARY_E3(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
#define BINARY_E4(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
#define BINARY_E5(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
#define BINARY_E6(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
#define BINARY_E7(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
#define BINARY_E8(n, arg) MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 0) )\
"," MACROCAT(BINARY_E, DECVAL(n)) ( DECVAL(n), MACROCAT(arg, 1) )
#define BINARY_ENUM(n) MACROCAT(BINARY_E, n) ( n, )
#define BIN_0(n, arg) TOSTRING ( arg )
#define BIN_1(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
"," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
#define BIN_2(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
"," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
#define BIN_3(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
"," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
#define BIN_4(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
"," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
#define BIN_5(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
"," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
#define BIN_6(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
"," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
#define BIN_7(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
"," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
#define BIN_8(n, arg) MACROCAT(BIN_, DECVAL(n)) (DECVAL(n), arg) \
"," MACROCAT(BINARY_E, DECVAL(n)) (DECVAL(n), MACROCAT(arg, 1))
#define BIN_ENUM(n) "0" MACROCAT(BIN_, n) ( n, )
测试代码:puts(BIN_ENUM(8));
测试考题不提供答案。

posted @ 2012-01-16 16:22 御坂美琴 阅读(7137) | 评论 (0)编辑 收藏

2011年12月27日 #

傻瓜学习C语言进制转换

最近受网友的邀请,就写一篇入门的教学文章。不过对于已经有一定实力水平的人来说,入门级的东西反而对于他(她)们来说不容易解释清楚,我也想挑战一下自己,看看我能把一些基础问题怎么解释能让智商80的人也能看明白(虽然这样说有点夸张),所以文章的标题就叫做“傻瓜学习C语言进制转换”,不过也不是没有要求的,要求是,看本文的时候,请你一定要按顺序看,并且要确定你会写这样一个c程序:输入一个int,分解出它的个位,十位,百位(提示:要用’%'求模运算和’/'整除运算)。。。。。。

1.数值与进制
数值与进制是两个不同的东西。数值是什么?100,200这种并不是数值。
什么是数值?古代的时候,人们记数,有一个物品就记一块石头,或者有11个物品,就打11个绳结,这就是数值,如果你要表示1000,那你还真的需要打1000个绳结来表示。可问题就是,这样子你会累死,为了不用累死,于是他们发明了另一种表达方式:准备两种不同的石头A和B,有一个,那就用一块A石头表示,两个就用两块A表示,如果太多了,比如10个,就用一块B石头来表示有10个A石头,比如AAAAABB表示25个。但是,如果表达的数值更大,那就再多准备一种石头C,每10个B石头就用一个C石头来表示,比如AABCC表示212。于是,这样就可以大大减少所需要的石头的数目,而这,就是进制。
进制是数值的一种表示方式

2.数值与进制的转化
进制是为了表示一个数值,如果是每10个进一,那么就是我们熟悉的10进制,否则,如果是每k个进一,那就是k进制,比如我们的时间,是每60秒记1分钟,这就是60进制。然后,怎么把一个用特定进制的表示,得到它的数值呢?很简单,比如上文说的AABCC,首先,有两个A,分解得AA + BCC,就是2 + BBC,然后,1个B就是10个A,于是就是AA + AAAAAAAAAA + AAAAAAAAAA + C,然后一个C等于10个B,就是AA + AAAAAAAAAA + AAAAAAAAAA + BBBBBBBBBB,这样一直拆下去,直到全部是A为止,你就得到实际的数值了,实际的数值就是A的个数,记住这一点,数值和进制是两码事。

然后,反过来,怎么把一个数值转化为特定进制呢?很简单,按照进制的定义,比如现在有数值AAAAAAAAAAAAAAAAAAAAAAA,然后,要转成10进制,那么我们每10个分一分组:AAAAAAAAAA + AAAAAAAAAA + AAA,然后,把10个A用B来表示,得到:B + B + AAA,如果B有10个,那再把它换成C表示。那么,如果你明白了以上方法,你就得到一个最基本的进制转换手段,就是先化为数值,再重新用另一个进制表示。比如10进制的13,要化成二进制,那么,就是BAAA -> AAAAAAAAAAA -> AA AA AA AA AA AA A 这时,换一个符号,每两个A用一个M表示,那么就是MM MM MM A,再每两个M用一个N表示,得到NN N A,再每两个N用一个P表示,得到P N A。而在这里,一个P等于8个A,一个N等于4个A,所以P + N + A你可以验算出8 + 4 + 1,等于原来的数值。而这种表示方法,就和罗马数字很相似,罗马数字里,用I表示1,用V表示5,用X表示10,于是18就用XVIII表达,用一个字母多次重复来表达一个数值。

后来,为了能更方便书写,因为字母数量是有限的,无法表达更大的数字,书写方式改用阿拉伯数字写在不同的位置来表达,于是就是我们今天的10进制数字。比如刚刚的例子,BAAA,有一个B,于是在十位写1,然后有三个B,在个位写3,也就是B的个数,组合起来就是13,这是十进制的情况。如果是二进制,刚刚我们得到的结果是PNA,注意这里没有M,相当于0个,而如果我们用二进制写,那就有四个位,个位有一个A,记1,第二位相当于M的个数,是0,组合起来是01,第三位是N,记1,组合是101,第四位有一个P,再组合就是1101,于是这就是10进制的13,化为二进制的结果。

3.进制的特点
问你,3638除以10的余数是多少?给你一秒种思考时间,多少?如果这个你不能马上说出来,那你就要反省了。结果应该是8,直接看个位不就对了。那么3638除以10的商呢?再给你一秒。。。。。。。。。。。。。。。。。。。这个答错的话要重读小学了,答案当然是363.8,如果把这个数取整,不要小数部分,那就是363。小学的时候你就应该知道,对一个数乘以10或者除以10这种计算是超简单的,因为我们用的是10进制。类似的,问一下你,经过60个5秒是多少分钟多少秒?再给你一秒思考时间,要毫不犹豫的回答我。你可别去计算60*5=300,这是多余的。答案是5分钟,时间我们用的60进制,那么乘以60只要改一下单位就足够了,肯定是对的。再问你,10分钟分成60份是多少秒?你必须立即回答我是10秒。
我们推广到任意k进制,按这个特点,k进制下,乘以k或者除以k的运算是超级简单的,比如8进制的123,乘以8肯定是1230,除以8就是12.3,相当于在移动小数点而已。于是,k进制下乘除k就是移动小数点。而除以k求余数的话,像刚刚的8进制的123除以8,就等于12余3,就是要得到个位上的数字,同时得到原来的数舍弃掉个位的结果。这个性质非常的重要!除法的本质是什么?其实除以k是得到被除数在k进制下的个位数(余数),和小数点左移的结果(商)。

4. C下实现数值转化为进制
好,现在回到程序,给你一个int n,要把它的各位上的数字取出来,按上面的性质,那就很简单了,先得到个位,n%10(这个’%'是求余运算),然后小数点左移,n = n / 10; 然后不断循环这个过程,如下代码:

int n = 2456;
while (n > 0)
{
    printf("%d,", n % 10);
    n = n / 10;
}

输出结果是”6,5,4,2,”,好好领悟一下这段代码。给你五分钟时间。每一次%10就是取出个位,每一次/10就是丢掉个位。
而如果把输出的结果里的数字,逆过来看,就是”2456″。

在这里,那个int所表示的,就是一个数值,刚刚我们的代码所做的事就是把这个数值,一位一位的分解出来。
而事实上,这个过程就是把数值转化为特定进制的过程。刚刚就是把数值转化为10进制。
如果把刚刚的代码改为:

int n = 13;
while (n > 0)
{
    printf("%d,", n % 2);
    n = n / 2;
}

没错,输出结果是”1,0,1,1″,就是刚刚把13化为二进制的例子,每一次%2就是取出二进制下的个位,每一次/2就是丢掉二进制下的个位。
只要把那个次序反过来,就得到1101,就是13化为二进制的结果。在你真正搞明白了除法的本质后,那么,数值转化为以k进制表示那是一件很简单的事。

5. 进制转化为数值
这部分我不打算讲,很多人对这个比起前面的内容来说容易理解很多,直接用进制的定义就已经很好办了,没什么太难理解的东西。

6. 作业
编写一个程序,输入三个整数n A B,表示把A进制的n,转换为B进制,并输出。
样例:
输入 输出
11 8 10 9
129 10 2 10000001
22 3 6 12

假定输入的A和B都在2-10这个范围,超出范围的不用去处理,输入的n保证在int范围内。

posted @ 2011-12-27 01:41 御坂美琴 阅读(1417) | 评论 (1)编辑 收藏

仅列出标题