导航:首页 > 源码编译 > printf源码分析

printf源码分析

发布时间:2022-06-20 08:50:16

① C语言中将int以%f输出时为何为0

printf不会替你转换数据。

编译的时候编译器不可能知道printf需要什么数据,所以不会转换。
运行的时候printf不知道你的数据是以什么类型传入的,还是不会转换。

你把int数据用%f输出,相当于输出了一个相同二进制形式的float数据(假设你是TC的话)

____

没有发生浮点运算的编译器是不会载入浮点库的,所以会抱错。

发现printf打印浮点数有问题。二进制是0x00000000xxxxxxxx的double应该是+Denormal但是printf输出的是0...

VC里%f对应的是double,如果你只传入一个int的话,相当于只提供了这个double的低4字节,而接下来的四个字节刚好是main保存寄存器的位置,一般来说刚好是0,就拼凑出了0x00000000xxxxxxxx的形态。所以printf会打印出0

② 求C语言中的库函数的源代码 如printf()函数,我要它的源代码

如果你安装的Visual Studio,以及它的Visual C++的话,
那么在安装目录下的VC/crt/src下有所有标准C库的源代码

另外,h后缀的头文件包含函数的声明,具体的实现都在c后缀的源码文件中

③ 跪求c语言中printf源码 ,即__vprinter源码

这个。。。你想干什么。。。

linux下C语言的printf原理是什么

Linux下C语言的printf是C标准I/O库中的格式化输出函数之一,将格式化数据写到标准输出stdout。
1 printf首先把格式化数据写到标准I/O的缓存,可以用setbuf和setvbuf设置缓存选项;
2 调用write系统调用,把标准I/O的缓存数据写到文件描述符STDOUT_FILENO,则标准I/O缓存中的数据就被送到内核缓存;
3 内核把缓存中的数据输出到标准输出stdout对应的文件描述符STDOUT_FILENO。
这是我的理解,基本应该就是这个流程,内核层次上的细节我就不清楚了。
另外:
1 printf返回写入的字节数;
2 printf处理可变参数表使用的是va_list,当然也有相应的vprintf,它的第三个参数就是一个va_list

⑤ c语言 高手请

很简单啊。。

结果是321.

首先你应该学过,指针是指向数组首地址,即*p=1;
根据++运算,*p++=1;
则运算*p++,*p++,*p++结果是1,2,3;

但是printf函数是从右至左输出<这点可以去看书得证>,因此变成了3,2,1.。
输出也即是321

⑥ printf函数的实现方式

其实printf和getchar()类似,它们都是一个”外壳“,真正实现功能的不是它本身,而是通过调用别的函数。
getchar() is equivalent to getc(stdin).
printf有一家子print函数

printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - formatted output conversion
它们的声明在不同的header file里面

#include <stdio.h>

int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);

#include <stdarg.h>

int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
snprintf(), vsnprintf():
这两个函数是C99新加的,编译的时候 注意 -std=c99

实现之前还是“复习”一下printf比较好,就当是铺垫
有意思的是printf的declaration。
int printf(const char *format, ...);
返回值是int,第一个参数是const字符串指针,第二个参数是个...
先看看返回值int有哪些情况
Return value
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).

嗯哼。。。返回的是成功打印的字符的个数,这里不包括NULL
demo:
#include<stdio.h>

int main()
{
int counter = 0;

counter = printf("hello world! %d\n",10);

printf("counter is %d\n",counter);

return 0;
}
jasonleaster@ubuntu:~$ ./a.out
hello world! 10
counter is 16

接着,第一个参数是一个指针,指向const字符串
Format of the format string
The format string is a character string, beginning and ending in its initial shift state, if any. The format string is composed of
zero or more directives: ordinary characters (not %), which are copied unchanged to the output stream; and conversion specifications,
each of which results in fetching zero or more subsequent arguments. Each conversion specification is introced by the character %,
and ends with a conversion specifier. In between there may be (in this order) zero or more flags, an optional minimum field width,
an optional precision and an optional length modifier.

很少人会用下面这种用法
printf("%*d",10,5);
我第一次遇到的时候,可以说是“惊愕”,究竟会打印什么东西。折腾了好久,最后搞定了。总结在这里
http://blog.csdn.net/cinmyheart/article/details/10116359

Format of the format string

The format string is a character string, beginning and ending in its initial shift state, if any. The format string is composed of zero or more directives: ordinary characters (not %), which are copied unchanged to the output stream; and conversion specifications, each of which results in fetching zero or more subsequent arguments. Each conversion specification is introced by the character %, and ends with a conversion specifier. In between there may be (in this order) zero or more flags, an optional minimum field width, an optional precision and an optional length modifier.
The arguments must correspond properly (after type promotion) with the conversion specifier. By default, the arguments are used in the order given, where each '*' and each conversion specifier asks for the next argument (and it is an error if insufficiently many arguments are given). One can also specify explicitly which argument is taken, at each place where an argument is required, by writing "%m$" instead of '%' and "*m$" instead of '*', where the decimal integer m denotes the position in the argument list of the
desired argument, indexed starting from 1. Thus,
printf("%*d", width, num);
and
printf("%2$*1$d", width, num);
are equivalent. The second style allows repeated references to the same argument. The C99 standard does not include the style using '$', which comes from the Single UNIX Specification. If the style using '$' is used, it must be used throughout for all conversions taking an argument and all width and precision arguments, but it may be mixed with "%%" formats which do not consume an argument.
There may be no gaps in the numbers of arguments specified using '$'; for example, if arguments 1 and 3 are specified, argument 2
must also be specified somewhere in the format string.

第三个参数 ...
嗯,这家伙有点屌,叫做变长参数。把这个搞定,C总会有点长进的
这个stdarg.h 我在现在的GCC和现在的linux 3.0版本的内核里面找了好久,都木有,估计是封装到被的地方了。。。。
__builtin_va_start(v,l) 线索就死在这个地方。。。之后就找不到__builtin_va_start的定义了

还是看早起内核的实现吧
0.12内核里面的stdarg.h
#ifndef _STDARG_H
#define _STDARG_H

typedef char *va_list;

/* Amount of space required in an argument list for an arg of type TYPE.
TYPE may alternatively be an expression whose type is used. */

#define __va_rounded_size(TYPE) \
(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

#ifndef __sparc__
#define va_start(AP, LASTARG) \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#else
#define va_start(AP, LASTARG) \
(__builtin_saveregs (), \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))
#endif

void va_end (va_list); /* Defined in gnulib */
#define va_end(AP)

#define va_arg(AP, TYPE) \
(AP += __va_rounded_size (TYPE), \
*((TYPE *) (AP - __va_rounded_size (TYPE))))

#endif /* _STDARG_H */

va_list 是一个指向字符串的指针
分析上面的宏定义#define __va_rounded_size(TYPE) \
(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
这个用来得到TYPE元素类型的字节大小,若不足4字节(例如short 和char),那么认为这个元素的大小为4字节,简单的说就是检测元素的大小,不足4字节的当作4字节看待。。。#define va_start(AP, LASTARG) \
(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))

AP一般都是va_list,LASTARG则是 指向参数变长函数的格式化字符串的指针.
va_start的作用就很明显了。取得变长参数列表的第一个参数的地址。
va_end 则是把指针va_list 置0 (通过google知道的,这个va_end真没找到定义,代码里面就一句#define 我无能为力啊。。。)
不过知道用va_start 和va_end 就OK啦
下面先来个变长参数的demo
/*****************************************************************************
code writer : EOF
code date : 2014.04.26
e-mail:[email protected]
code purpose:
just a demo for varible parameter function.

usage: va_sum(a number,anohter number...,0);
va_sum(1,2,3,4,5,0); return 15

******************************************************************************/

#include <stdarg.h>
#include <stdio.h>

int va_sum(int* a,...);

int main()
{
int number = 1;

int foo = 0;

foo = va_sum(&number,2,3,4,5,0);

return 0;
}

int va_sum(int* a,...)
{
int counter = 0;
int element = 0;

va_list arg;

va_start(arg,a);

while((element = va_arg(arg,int)) != 0)
{
counter += element;
}

va_end(arg);

return counter;
}

#define va_arg(AP, TYPE) \
(AP += __va_rounded_size (TYPE), \
*((TYPE *) (AP - __va_rounded_size (TYPE))))

⑦ printf的问题

首先,总结性地回答:
windows和linux和Dos三种操作系统的printf源码应该是略有区别的。
其次,介绍一下printf的底层显示函数。
printf是在屏幕上打印一个字符串的函数。
(注:数字其实也是按照字符的形式显示在屏幕上的。)
因为printf其实是解析format格式,例如%d,\n,等等。

真正在屏幕上显示的函数是决定与操作系统底层的。
也就是都是调用底层的显示策略函数实现的在屏幕的指定位置进行显示。

例如:stdio.h中的printf.c的源码中:
printChar函数就是顶层的显示策略函数。

code]int putchar (int c) {
switch ((unsigned char) c) {
case '\n' :
newLine ();
break;
case '\r' :
carriageReturn ();
break;
case '\f' :
clearScreen ();
break;
case '\t' :
printChar (32); printChar (32); /* 32 = space */
printChar (32); printChar (32);
printChar (32); printChar (32);
printChar (32); printChar (32);
break;
case '\b':
backspace ();
break;
case '\a':
beep ();
break;
default :
printChar ((unsigned char) c);
}
return c;
}[/code]

接下来看printChar也就是输出部分最低层的操作咯

[code]void printChar (const byte ch) {
*(word *)(VIDEO + y * 160 + x * 2) = ch | (fill_color << 8);
x++;
if (x >= WIDTH)
newLine ();
setVideoCursor (y, x);
}[/code]这里VIDEO表示显存地址也就是0xB8000.通过 y * 160 + x 屏幕(x,y)坐标在显存中的位置.这里需要知道,一个字符显示需要两个字节,一个是ASCII码,第二个是字符属性代码也就是颜色代码.因此才必须 y * 80 * 2 + x = y * 160 + x.那么ch | (fill_color << 8)也自然就是写入字符及属性代码用的了.每写一个字符光标位置加1,如果大于屏幕宽度WIDTH就换行.最后通过setVideoCursor设置新的光标位置.完成了整个printChar过程.

⑧ 为什么学完C语言,我还是看不懂printf的源代码

你写的C语言只是在编译器上写的,printf这个系统函数的实现跟编译器有关,编译器下面是操作系统,所以你肯定写不出来撒。

printf可以有很多参数,可以输入不定量个参数,并不是简单的输出。

反正你现在只要知道这个很复杂就行了,要学的东西以后你会慢慢学的,欲速则不达。

⑨ C语言中printf是库函数,那么printf的代码到底在哪里呢

书上说的没错,lib文件中存放的就是被调用系统函数的目标代码,但是和声明文件一样不是一个函数一个文件,而是一批函数放在一个文件里。并且文件是二进制的格式,你也查看不了。
对于.h头文件你理解的没错,头文件是只是函数的声明,里面不放函数的具体代码,具体代码比如VC是在C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src 目录下,你可以找到printf.c文件的源码,如果你是想看源码就看这个。我看了其它人的回复,C编译器的不同位置放的是不同的函数部分,以VC为例,include放的是调用函数的声明部分,并且只有声明部分;src目录放的是函数的源码;lib放的是函数的编译后目标文件,但是是打捆放的,代码只有在链接时,才会将库函数进行连接,并生成最后的EXE可执行文件。

⑩ C语言源代码分析(越易懂越好,我只是一个初学者)

printf“”里的是原样输出的东西,但是你的y是未知的,是你程序运行到这一步才可以得到的,你没有办法写到“”里,所以你用%d代替,%d不会原样输出,它代表整数,而你的y的数值就是%d的数值,就是当printf里有%d的时候程序知道它的数值是“”,后跟的那个数,也就是这个程序里的y,比如printf(“%d%d%d”,a,b,c);第一个%d输出的是a的值,第二个%d输出的是b的值,第三个就是c的值了,如果是%c就是字符的意思,%f就是浮点型的数

阅读全文

与printf源码分析相关的资料

热点内容
程序员苹果全家桶 浏览:195
远程命令阻塞 浏览:728
有网页源码怎么查数据 浏览:99
win10下make编译速度过慢 浏览:864
微机原理编译环境 浏览:17
怎么把图纸转换成pdf 浏览:539
安卓libcurl编译64 浏览:903
手机app怎么测速 浏览:275
中兴gpon命令 浏览:885
python中取出字典key值 浏览:680
Linux目录inode 浏览:147
手机上如何用文件夹发邮件 浏览:428
畅课app密码忘了怎么找回 浏览:79
怎么编译idea 浏览:231
如何查看服务器是否做了热备 浏览:1001
硬盘同名文件夹病毒 浏览:729
百度云不解压下载 浏览:563
新冠疫情app怎么用 浏览:973
拆二代程序员 浏览:400
河北压缩空气冷干机生产厂家 浏览:582