我写的一个程序里面有多个printf输出格式函数输出有问题

一个C程序中只能有一个printf语句吗【c语言吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:530,251贴子:
一个C程序中只能有一个printf语句吗收藏
为什么我写的一个程序,输出的结果总是最后一个printf的输出结果
基因敲除小鼠模型,经验丰富,最快只需1个月
要多少个随你
你把代码贴上来撒,或者M我
总算看到比我还菜的问题了
那是你自己的程序结构有问题,
Effective C, item #0: There should be only one printf statement in a C program.
总算找到比我还菜的+1内流满面
什么是printf语句。。。
可以有多个
北京八方利元税务师事务所专业提供各种税收筹划等服务
看到你,我找到了,希望!~
尼玛第一次看到这种神奇的问题
任何函数理论都可以调用无限次.
这算什么..
总算找到比我还菜的+1内流满面终于找到了
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或21ic官方微信-->
后使用快捷导航没有帐号?
查看: 6396|回复: 10
关于单片机程序中使用printf函数的问题
&&已结帖(50)
主题帖子积分
中级技术员, 积分 251, 距离下一级还需 49 积分
中级技术员, 积分 251, 距离下一级还需 49 积分
主题帖子积分
专家等级:结帖率:87%
主题帖子积分
中级技术员, 积分 251, 距离下一级还需 49 积分
中级技术员, 积分 251, 距离下一级还需 49 积分
下面这段代码是C8051F34x中串口调试的例程,可以用printf函数来打印串口调试信息。不明白是怎么实现的,貌似通常情况下,printf函数是需要改造一下才能用来打印信息的,请高手帮忙答疑,谢谢了.
#include &c.h&& && && && && &&&// SFR declarations
#include &stdio.h&
#define SYSCLK& && && && && &&&// SYSCLK frequency in Hz
#define BAUDRATE& && &&&9600& && && &&&// Baud rate of UART in bps
void SYSCLK_Init (void);
void UART0_Init (void);
void PORT_Init (void);
void Timer2_Init (int);
void main (void)
& &unsigned& && & // Used to store character from UART
& &PCA0MD &= ~0x40;& && && && && && &&&// WDTE = 0 (clear watchdog timer
& && && && && && && && && && && && && &// enable)
& &PORT_Init();& && && && && && && && &// Initialize Port I/O
& &SYSCLK_Init ();& && && && && && && &// Initialize Oscillator
& &UART0_Init();
& &while (1)
& && &printf (&\nEnter character: &);
& && &inputcharacter = getchar ();
& && &printf (&\nCharacter entered : %c&,inputcharacter);
& && &printf (&\n& && &Value in Hex: %bx&,inputcharacter);
void PORT_Init (void)
& &P0MDOUT |= 0x10;& && && && && && &&&// Enable UTX as push-pull output
& &XBR0& &&&= 0x01;& && && && && && &&&// Enable UART on P0.4(TX) and P0.5(RX)& && && && && && && &
& &XBR1& &&&= 0x40;& && && && && && &&&// Enable crossbar and weak pull-ups
void SYSCLK_Init (void)
& &OSCICN |= 0x03;& && && && && && && &// Configure internal oscillator for
& && && && && && && && && && && && && &// its maximum frequency
& &RSTSRC&&= 0x04;& && && && && && && &// Enable missing clock detector
void UART0_Init (void)
& &SCON0 = 0x10;& && && && && && && &&&// SCON0: 8-bit variable bit rate
& && && && && && && && && && && && && &//& && &&&level of STOP bit is ignored
& && && && && && && && && && && && && &//& && &&&RX enabled
& && && && && && && && && && && && && &//& && &&&ninth bits are zeros
& && && && && && && && && && && && && &//& && &&&clear RI0 and TI0 bits
& &if (SYSCLK/BAUDRATE/2/256 & 1) {
& && &TH1 = -(SYSCLK/BAUDRATE/2);
& && &CKCON &= ~0x0B;& && && && && && &// T1M = 1; SCA1:0 = xx
& && &CKCON |=&&0x08;
& &} else if (SYSCLK/BAUDRATE/2/256 & 4) {
& && &TH1 = -(SYSCLK/BAUDRATE/2/4);
& && &CKCON &= ~0x0B;& && && && && && &// T1M = 0; SCA1:0 = 01& && && && && && &
& && &CKCON |=&&0x01;
& &} else if (SYSCLK/BAUDRATE/2/256 & 12) {
& && &TH1 = -(SYSCLK/BAUDRATE/2/12);
& && &CKCON &= ~0x0B;& && && && && && &// T1M = 0; SCA1:0 = 00
& &} else {
& && &TH1 = -(SYSCLK/BAUDRATE/2/48);
& && &CKCON &= ~0x0B;& && && && && && &// T1M = 0; SCA1:0 = 10
& && &CKCON |=&&0x02;
& &TL1 = TH1;& && && && && && && && &&&// Init Timer1
& &TMOD &= ~0xf0;& && && && && && && & // TMOD: timer 1 in 8-bit autoreload
& &TMOD |=&&0x20;& && && && && && && &&&
& &TR1 = 1;& && && && && && && && && & // START Timer1
& &TI0 = 1;& && && && && && && && && & // Indicate TX0 ready
, , , , , , ,
满意回复+50
只要初始化串口,就能用Printf函数将相关内容送串口了,注意一定要在初始化完成后加上一句
TI=1;让putchar能顺利将字符经由51单片机的串口发送出去。
因为这个 ...
山外青山楼外楼
主题帖子积分
中级技术员, 积分 251, 距离下一级还需 49 积分
中级技术员, 积分 251, 距离下一级还需 49 积分
主题帖子积分
专家等级:结帖率:87%
主题帖子积分
中级技术员, 积分 251, 距离下一级还需 49 积分
中级技术员, 积分 251, 距离下一级还需 49 积分
在网上看到单片机程序中使用printf的例子,一般都是经过了改造的;但是上面的程序没有任何改造,是直接调用的,也确确实实可以从串口打印信息,请高手帮忙解释一下
山外青山楼外楼
主题帖子积分
主题帖子积分
专家等级:结帖率:100%打赏:0.10受赏:5.10
主题帖子积分
在51中& &printf&&链接 C 编译库中的 putchar
在M3或M0&&它调用sendchar& & 注意retarget.c
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
主题帖子积分
专家等级:结帖率:100%打赏:0.10受赏:5.10
主题帖子积分
在51中& &printf&&链接 C 编译库中的 putchar
在M3或M0&&它调用sendchar& & 注意retarget.c
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
技术总监, 积分 40070, 距离下一级还需 9930 积分
技术总监, 积分 40070, 距离下一级还需 9930 积分
主题帖子积分
专家等级:结帖率:3%
主题帖子积分
技术总监, 积分 40070, 距离下一级还需 9930 积分
技术总监, 积分 40070, 距离下一级还需 9930 积分
默认直接与串口打交道
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
主题帖子积分
专家等级:结帖率:91%
主题帖子积分
只要初始化串口,就能用Printf函数将相关内容送串口了,注意一定要在初始化完成后加上一句
TI=1;让putchar能顺利将字符经由51单片机的串口发送出去。
因为这个函数是类如下步骤完成的。
while(TI == 0);
SBUF=ucWriteD
以VS1003B和山景SOC芯片为背景,倾心研制数字化语音录放产品.
排忧邮箱:xg_2004_
得意之作是做了个AVR高压编程器,用起来爽歪歪,
串口MP3录放音模块,全面进入数字录放音时代
主题帖子积分
中级技术员, 积分 251, 距离下一级还需 49 积分
中级技术员, 积分 251, 距离下一级还需 49 积分
主题帖子积分
专家等级:结帖率:87%
主题帖子积分
中级技术员, 积分 251, 距离下一级还需 49 积分
中级技术员, 积分 251, 距离下一级还需 49 积分
谢谢古道热肠的回复,受用了,以前用printf打印不成功,所以总是自己在程序中写个putchar 函数,可以打印字符和字符串,用printf调试时就方便多了。
山外青山楼外楼
主题帖子积分
初级工程师, 积分 2951, 距离下一级还需 49 积分
初级工程师, 积分 2951, 距离下一级还需 49 积分
主题帖子积分
专家等级:结帖率:20%打赏:0.00受赏:8.00
主题帖子积分
初级工程师, 积分 2951, 距离下一级还需 49 积分
初级工程师, 积分 2951, 距离下一级还需 49 积分
只要初始化串口,就能用Printf函数将相关内容送串口了,注意一定要在初始化完成后加上一句
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
中级技术员, 积分 178, 距离下一级还需 122 积分
中级技术员, 积分 178, 距离下一级还需 122 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
中级技术员, 积分 178, 距离下一级还需 122 积分
中级技术员, 积分 178, 距离下一级还需 122 积分
我很好奇&&printf 这货是怎么找到串口并且发送数据的&&pringtf相当于上层应用程序&&串口配置相当于底层硬件驱动 这两货是怎么手牵手 发数据的&&有高手吧这过程解释详细点吗&&
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
中级技术员, 积分 178, 距离下一级还需 122 积分
中级技术员, 积分 178, 距离下一级还需 122 积分
主题帖子积分
专家等级:结帖率:0%
主题帖子积分
中级技术员, 积分 178, 距离下一级还需 122 积分
中级技术员, 积分 178, 距离下一级还需 122 积分
假如说 我的单片机有两个串口& &两个都初始化了&&她会怎么去选择 最好能附有代码说明
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
主题帖子积分
中级技术员, 积分 132, 距离下一级还需 168 积分
中级技术员, 积分 132, 距离下一级还需 168 积分
主题帖子积分
专家等级:结帖率:80%
主题帖子积分
中级技术员, 积分 132, 距离下一级还需 168 积分
中级技术员, 积分 132, 距离下一级还需 168 积分
谢谢热肠兄,果然可以了,不过也是和楼上的有同样的疑问
21ic公开课,21ic网友共同的学习圈子!学单片机、嵌入式、模拟、电源……就看这里
移步更多21ic独家微课:
时间类勋章
技术奇才奖章
人才类勋章
无冕之王奖章
等级类勋章
沉静之湖泊
发帖类勋章
时间类勋章
技术高手奖章
人才类勋章
荣誉元老奖章
等级类勋章
坚毅之洋流
发帖类勋章
时间类勋章
技术领袖奖章
人才类勋章
涓涓之细流
发帖类勋章
技术新星奖章
人才类勋章
热门推荐 /1遇到printf输出问题 - 博客频道 - CSDN.NET
SAY SOMETHING
分类:C语言
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -------------------------------------------------------Sun---------------------------------------------------------------------------
在牛客遇到此问题:
int main()
&&& float b,c;
&&& scanf(&%2d%3f%4f&,&a,&b,&c);
&&& printf(&\na=%d,b=%d,c=%f\n&,a,b,c);
&&& return 0;
输入l,结果是:
codeblocks下
Linux下&&&&&&&&&
总之和编译器有关啦(⊙o⊙)…
补充基础知识:
一、printf()函数&&
& printf()函数是格式化输出函数,&一般用于向标准输出设备按规定格式输出信息。在编写程序时经常会用到此函数。
& printf()函数的调用格式为:& printf(&&格式化字符串&&,&&参量表&);&&
& 其中格式化字符串包括两部分内容:&一部分是正常字符,&这些字符将按原样输出;&另一部分是格式化规定字符,&以&%&开始,&后跟一个或几个规定字符,& 用来确定输出内容格式。&&
& 参量表是需要输出的一系列参数,&其个数必须与格式化字符串所说明的输出参数个数一样多,&各参数之间用&,&分开,&且顺序一一对应,&否则将会出现意想不到的错误。
1.&格式化规定符&&
%d&十进制有符号整数&&
%u&十进制无符号整数&&
%f&浮点数&&
%s&字符串&&
%c&单个字符&&
%p&指针的值&&
%e&指数形式的浮点数&&
%x,&%X&无符号以十六进制表示的整数&&
%0&无符号以八进制表示的整数&&
%g&自动选择合适的表示法&&
(1).&可以在&%&和字母之间插进数字表示最大场宽。&&
例如:&%3d&表示输出3位整型数,&不够3位右对齐。& %9.2f&表示输出场宽为9的浮点数,&其中小数位为2,&整数位为6, 小数点占一位,&不够9位右对齐。&&
&&&&&&&&& %8s&表示输出8个字符的字符串,&不够8个字符右对齐。&&
&&&&&&&&& 如果字符串的长度、或整型数位数超过说明的场宽,&将按其实际长度输出。但对浮点数,&若整数部分位数超过了说明的整数位宽度,&将按实际整数位输出;& 若小数部分位数超过了说明的小数位宽度,&则按说明的宽度以四舍五入输出。 另外,&若想在输出值前加一些0,&就应在场宽项前加个0。&&
例如:&%04d&表示在输出一个小于4位的数值时,&将在前面补0使其总宽度为4位。&
如果用浮点数表示字符或整型量的输出格式,&小数点后的数字代表最大宽度,& 小数点前的数字代表最小宽度。&&
例如:&%6.9s&表示显示一个长度不小于6且不大于9的字符串。若大于9,&则第9个字符以后的内容将被删除。
(2).&可以在&%&和字母之间加小写字母l,&表示输出的是长型数。&&
例如:&%ld&表示输出long整数& %lf&表示输出double浮点数&
(3).&可以控制输出左对齐或右对齐,&即在&%&和字母之间加入一个&-&&号可说明输出为左对齐,&否则为右对齐。&&
例如:&%-7d&表示输出7位整数左对齐&&
&&&&&&&&& %-10s&表示输出10个字符左对齐&
2.&一些特殊规定字符&
\f&清屏并换页&&
\t&Tab符&&
\xhh&表示一个ASCII码用16进表示,&&
其中hh是1到2个16进制数&&
int&main()&
&&& char&c,&s[20],&*p;&
&&& int&a=1234,&*i;&
&&& float&f=3.;&
&&& double&x=0.54321;&
&&& p=&How&do&you&do&;&
&&& strcpy(s,&&Hello,&Comrade&);&
&&& *i=12;&
&&& c='\x41';&
&&& printf(&a=%d\n&,&a);&/*结果输出十进制整数a=1234*/&
printf(&a=%6d\n&,&a);&/*结果输出6位十进制数a=&1234*/&
printf(&a=%06d\n&,&a);&/*结果输出6位十进制数a=001234*/&
printf(&a=%2d\n&,&a);&/*a超过2位,&按实际值输出a=1234*/&
printf(&*i=%4d\n&,&*i);&/*输出4位十进制整数*i=&12*/&
printf(&*i=%-4d\n&,&*i);&/*输出左对齐4位十进制整数*i=12*/&
printf(&i=%p\n&,&i);&/*输出地址i=06E4*/&
printf(&f=%f\n&,&f);&/*输出浮点数f=3.141593*/&
printf(&f=6.4f\n&,&f);&/*输出6位其中小数点后4位的浮点数 f=3.1416*/&
printf(&x=%lf\n&,&x);&/*输出长浮点数x=0.123457*/&
printf(&x=%18.16lf\n&,&x);/*输出18位其中小数点后16位的长浮点数x=0.5432*/&
printf(&c=%c\n&,&c);&/*输出字符c=A*/&
printf(&c=%x\n&,&c);&/*输出字符的ASCII码值c=41*/&
printf(&s[]=%s\n&,&s);&/*输出数组字符串s[]=Hello,&Comrade*/&
printf(&s[]=%6.9s\n&,&s);/*输出最多9个字符的字符串s[]=Hello, Co*/&
&&& printf(&s=%p\n&,&s);&/*输出数组字符串首字符地址s=FFBE*/&
&&& printf(&*p=%s\n&,&p);&/*&输出指针字符串p=How&do&you&do*/&
&&& printf(&p=%p\n&,&p);&/*输出指针的值p=0194*/&
&&& getchar();&
&&& retunr&0;&
二、scanf()函数&
& scanf()函数是格式化输入函数,&它从标准输入设备(键盘)&读取输入的信息。&
& 其调用格式为:&
& scanf(&&格式化字符串&&,&&地址表&);&
& 格式化字符串包括以下三类不同的字符;&
1.&格式化说明符:&格式化说明符与printf()函数中的格式说明符基本相同。&
2.&空白字符:&空白字符会使scanf()函数在读操作中略去输入中的一个或多个空白字符。&
3.&非空白字符:&一个非空白字符会使scanf()函数在读入时剔除掉与这个非空白字符相同的字符。
地址表是需要读入的所有变量的地址,&而不是变量本身。这与printf()函数完全不同,&要特别注意。各个变量的地址之间同&,&分开。
int main()&
int&i,&j;&
printf(&i,&j=?\n&);&
scanf(&%d,&%d&,&&i,&&j);&
上例中的scanf()函数先读一个整型数,&然后把接着输入的逗号剔除掉,&最后读入另一个整型数。如果&,&这一特定字符没有找到,&scanf()函数就终止。若参数之间的分隔符为空格,&则参数之间必须输入一个或多个空格。&
(1).&对于字符串数组或字符串指针变量,&由于数组名和指针变量名本身就是地址,&因此使用scanf()函数时,&不需要在它们前面加上&&&操作符。
int main()
char&*p,&str[20];&
scanf(&%s&,&p);&/*从健盘输入字符串*/&
scanf(&%s&,&str);&
printf(&%s\n&,&p);&/*向屏幕输出字符串*/&
printf(&%s\n&,&str);&
(2).&可以在格式化字符串中的&%&各格式化规定符之间加入一个整数,&表示任何读操作中的最大位数。&
如例3中若规定只能输入10字符给字符串指针p,&则第一条scanf()&函数语句变为scanf(&%10s&,&p);&
程序运行时一旦输入字符个数大于10,&p就不再继续读入,&而后面的一个读入函数即scanf(&%s&,&str)就会从第11个字符开始读入。&
实际使用scanf()函数时存在一个问题,&下面举例进行说明: 当使用多个scanf()函数连续给多个字符变量输入时,&例如:&
int main()&
char&c1,&c2;&
scanf(&%c&,&&c1);&
scanf(&%c&,&&c2);&
printf(&c1&is&%c,&c2&is&%c&,&c2\1,&c2);&
运行该程序,&输入一个字符A后回车&(要完成输入必须回车),&在执行scanf (&%c&,&&c1)时,&给变量c1赋值&A&,&但回车符仍然留在缓冲区内,&执行输入语句&
scanf(&%c&,&&c2)时,&变量c2输出的是一空行,&如果输入AB后回车,&那么输出结果为:&c1&is&A,&c2&is&B。&
要解决以上问题,&可以在输入函数前加入清除函数fflush()(&这个函数的使用方法将在本节最后讲述)。修改以上程序变成:&
char&c1,&c2;&
scanf(&%c&,&&c1);&
fflush(stdin);&
scanf(&%c&,&&c2);&
printf(&c1&is&%c,&c2&is&%c&,&c1,&c2);&
非格式化输入输出函数&
非格式化输入输出函数可以由上面讲述的标准格式化输入输出函数代替,&但这些函数编译后代码少,&相对占用内存也小,&从而提高了速度,&同时使用也比较方便。
一、puts()和gets()函数&
1.&puts()函数&
puts()函数用来向标准输出设备(屏幕)写字符串并换行,&其调用格式为: puts(s);&
其中s为字符串变量(字符串数组名或字符串指针)。 puts()函数的作用与语printf(&%s\n&,&s)相同。&
char&s[20],&*f;&/*定义字符串数组和指针变量*/&
strcpy(s,&&Hello!&);&/*字符串数组变量赋值*/&
f=&Thank&you&;&/*字符串指针变量赋值*/&
(1).&puts()函数只能输出字符串,&不能输出数值或进行格式变换。&
(2).&可以将字符串直接写入puts()函数中。如:&
puts(&Hello,&Turbo&C2.0&);&
2.&gets()函数&
gets()函数用来从标准输入设备(键盘)读取字符串直到回车结束,&但回车符不属于这个字符串。其调用格式为: gets(s);&
其中s为字符串变量(字符串数组名或字符串指针)。&
gets(s)函数与scanf(&%s&,&&s)相似,&但不完全相同,&使用scanf(&%s&,&&s) 函数输入字符串时存在一个问题,&就是如果输入了空格会认为输入字符串结束, 空格后的字符将作为下一个输入项处理,&但gets()&函数将接收输入的整个字符串直到回车为止。
char&s[20],&*f;&
printf(&What's&your&name?\n&);&
gets(s);&/*等待输入字符串直到回车结束*/&
puts(s);&/*将输入的字符串输出*/&
puts(&How&old&are&you?&);&
排名:千里之外
(18)(1)(10)(10)(0)如何写参数个数不定的函数(即类似printf的函数)
我的图书馆
如何写参数个数不定的函数(即类似printf的函数)
#include &stdio.h&
#include &stdarg.h&&&&&&&&&//要包含这个头文件
void variable(int i, ...)
arg_&&&&//第1步,定义这个指向参数列表的变量
va_start(arg_ptr, i);//第2步,把上面这个变量初始化.即让它指向参数列表
&&&&while(
&&&&&&&&//第3步,获取arg_ptr指向的当前参数.这个参数的类型由va_arg的第2个参数指定
j = va_arg(arg_ptr, int);
printf("%d ",j );
va_end(arg_ptr);&&&&//第4步,做一些清理工作
variable(3, 3,
//////////////////////////
//////////////////////////
//////////////////////////
///////作为va_list,va_start的练习,可以学习一下使用_vsnprintf函数
#include &stdarg.h&
void formatoutput(char* format, ...)
va_list arg_
va_start(arg_ptr, format);
_vsnprintf(s, sizeof(s)-1, format,
printf("%s ", s);
void main()
formatoutput("%s%s",
////////////////////
/////////////////////
参数个数不定的函数,最频繁使用的就是printf()与scanf()。其实,我们也可以自己实现这样的功能,首先看
一个例子:
&stdarg.h&
int Sum(int first,
int second, ...)
int sum = 0, t =
va_start(vl, first);
while (t != -1)
t = va_arg(vl, int);//将当前参数转换为int类型
va_end(vl);
int main(int argc,
char* argv[])
printf("The sum is %d\n", Sum(30, 20, 10, -1));//-1是参数结束标志
在上面的例子中,实现了一个参数个数不定的求int型和的函数Sum()。函数中一开始定义了一个va_list型变量
vl,该变量用来访问可变参数,实际上就是指针,接着使用va_start使vl指向第一个参数,然后再使用va_arg
来遍历每一个参数,va_arg返回参数列表中的当前参数并使vl指向参数列表中的下一个参数。最后通过va_end
把vl指针清为NULL。在这里,va_start,va_arg,va_end其实都是宏,那么这些宏又是如何实现他们的功能的
一个很显然的问题就是既然参数个数在函数调用之前没有确定,所以,在函数定义的时候没有办法像普通函数
那样使用确定的变量来接受传进来的参数,于是,问题的关键就是如何接收到这些不确定的参数了?首先,看
看函数调用时实际发生的情况,在函数调用的时候,使用栈传递参数,拿上例来说,如果调用Sum(30,
-1),那么参数入栈后的情形如下图所示(假定按照自右至左的顺序入栈):
既然参数在栈中的情形已经知道了,那么,如果使用指针(程序中的vl)指向第一个参数(va_start(vl,
first)),因为所有参数都是连续存放的,通过移动指针就可以访问到每一个参数了(va_arg(vl,
int)),这
就是我在程序中使用到那几个宏的实现思想。
明白了以上原理之后,就可以完全不使用宏,自己实现这样的一个功能了,下面的程序是我按照上面的
思想改写的:
int Sum(int first,
int second, ...)
int sum = 0, t =
char *//定义一个指针
vl = (char *)&//使指针指向第一个参数
while (*vl != -1)//-1是预先给定的结束符
sum += *(int *)//类型转换
vl += sizeof(int);//移动指针,使指针指向下一个参数
int main(int argc,
char* argv[])
printf("The sum is %d\n", Sum(30, 20, 10, -1));//-1是参数结束标志
可以看出,通过使用指针的确实现了参数个数不定的函数了,但是程序中还有一个问题,那就是移动指针,在
程序中因为我使用的参数都是相同的int类型,所以可以事先知道访问下一个参数的时候应该移动sizeof(int)
个字节,但是,如果参数的类型不同呢?这的确是个比较麻烦的问题,因为不同的数据类型占用的字节数可能
是不一样的(如double型为8个字符,short
int型为2个),所以很难事先确定应该移动多少个字节!但是办法
还是有的,这就是使用指针了,无论什么类型的指针,都是占用4个字节,所以,可以把所有的传人参数都设置
为指针,这样一来,就可以通过移动固定的4个字节来实现遍历可变参数的目的了,至于如果取得指针中的内容
并使用他们,当然也是无法预先得知的了,所以这大概也就是像printf(),scanf()之类的函数还需要一个格式
控制符的原因吧^_^!不过实现起来还是有不少麻烦,暂且盗用vprintf()来实现一个与printf()函数一样功能的
函数了,代码如下:
void myPrint(const
char *frm, ...)
&&& va_list
&&& va_start(vl,
&&& vprintf(frm,
va_end(vl);
//////////////////////
////////////////////////
书上说,当无法列出传递函数的所有实参的类型和数目时,可用省略号指定参数表(...)
如:void foo(...);
void foo(parm_list,...);
void foo(...)
调用:foo(a,b,c);
就是不懂,把a,b,c的值传进函数里面后,用什么变量来接收???如果不能接收,(...)岂不是没意义?
还有就是不明白
int printf(const char*...);
printf("hello,&s\n",userName);
这个c的输出函数是怎么用(...)实现的.
首先函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码:
void TestFun(char* pszDest, int DestLen, const char* pszFormat,
va_start(args, pszFormat);
_vsnprintf(pszDest, DestLen, pszFormat, args);
va_end(args);
///////////////////////////
一个简单的可变参数的C函数
先看例子程序。该函数至少有一个整数参数,其后占位符…,表示后面参数的个数不定。在这个例子里,所有的输入参数必须都是整数,函数的功能只是打印所有参数的值。函数代码如下:
//示例代码1:可变参数函数的使用#include
#include "stdarg.h"
void simple_va_fun(int start, ...)
va_list arg_
int nArgValue =
int nArgCout=0;&& //可变参数的数目
va_start(arg_ptr,start);&&
//以固定参数的地址为起点确定变参的内存起始地址。
printf("the %d th arg: %d",nArgCout,nArgValue); //输出各参数的值
nArgValue =
va_arg(arg_ptr,int);&&
//得到下一个可变参数的值
} while(nArgValue !=
-1);&&&&&&&&&&&&&&&&
int main(int argc, char* argv[])
simple_va_fun(100,-1);
simple_va_fun(100,200,-1);
下面解释一下这些代码。从这个函数的实现可以看到,我们使用可变参数应该有以下步骤:
⑴由于在程序中将用到以下这些宏:
va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
va在这里是variable-argument(可变参数)的意思。
这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件。
⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变量是存储参数地址的指针.因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。
⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,即最后一个固定参数。
⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后,结合参数的类型,就可以得到参数的值。
⑸设定结束条件,这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的,程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目,在看完这几个宏的内部实现机制后,自然就会明白。
1)可变参数的存储形式.
大家都知道,一般函数的形参属于局部变量.而局部变量就是存储在内存的栈区(所谓的栈区:由编译器自动分配释放,
存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。).可变参数也是存储在内存栈区.
在对函数的形参存储的时侯,编译器是从函数的形参的右边到左边逐一地压栈,
这样保证了栈顶是函数的形参的第一个参数(从左到右数).而80x86平台下的内存分配顺序是从高地址内存到低地址内存.
因此,函数的形参在内存的存储形式如下图(以fun(int var1,int var2,...,int var3,int
var4)为例):
&& & 低地址
|第一个固定参数var1
|可变参数前的第一个固定参数var2
|可变参数的第一个参数
|可变参数的最后一个参数
|函数的倒数第二个固定参数var3
|函数的最后一个固定参数var4
|函数的返回地址
|栈底& & 高地址
原文地址:
TA的最新馆藏

我要回帖

更多关于 printf 16进制输出 的文章

 

随机推荐