導航:首頁 > 源碼編譯 > 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源碼分析相關的資料

熱點內容
伺服器出現兩個IPV4地址 瀏覽:844
宜興雲存儲伺服器 瀏覽:221
如何開放遠程伺服器上的埠號 瀏覽:67
大規模單片機廠家供應 瀏覽:952
3dmax編輯樣條線快捷命令 瀏覽:708
怎麼獲得音樂的源碼 瀏覽:249
郭麒麟參加密室完整版 瀏覽:318
單片機排線怎麼用 瀏覽:483
java字元串太長 瀏覽:868
python變數計算 瀏覽:115
網銀pdf 瀏覽:134
iponedns伺服器怎麼設置復原 瀏覽:405
深圳電力巡檢自主導航演算法 瀏覽:436
十二星座的布娃娃怎麼買app 瀏覽:321
反編譯打包地圖不顯示 瀏覽:92
沒有壓縮的圖片格式 瀏覽:468
斯維爾文件需不需要加密狗 瀏覽:300
柱加密區范圍在軟體中設置 瀏覽:706
紙質音樂壓縮教程 瀏覽:33
安卓手機健康碼快捷方式怎麼設置 瀏覽:477