printf和標準輸出

2021-05-06 17:04:57 字數 3376 閱讀 7181

printf和標準輸出

printf和標準輸出

上次寫到main函式的引數傳遞.現在繼續往下進行.最近忙實驗室的事情,看了一周

的文章,也沒啥進展,週末寫點技術貼,放鬆一下:-)

進入main函式後,就要呼叫printf("hello world!

");了.順便將c語言引數傳遞提

一下.字串"hello world!

"編譯器是當作字串常量來處理的,雖然printf是在main

內部呼叫,但"hello world!

"可不是放在main的棧中,字串常量至少是放到.data段的

,準確說是放在唯讀資料段.rodata,這個我在工作站上驗證了一把.假如編輯的檔名是

hello.c,首先編譯生成elf格式二進位制檔案gcc hello.c -o hello然後用命令

objdump -s hello -s引數會將所有段資訊dump出來.你會看到"hello world!

"位於.rodata段.

printf()是個標準c庫函式.雖然功能簡單,但實現起來卻不容易.這是個和平台相關的

函式.在pc上,printf輸出是輸出到終端螢幕,在嵌入式裝置上,一般printf()是輸出到串列埠.

同是呼叫printf(),最終輸出的裝置卻不同,從直覺的肯定是感覺printf()底層和平台是相

關的.那麼printf()是怎樣實現的呢?

可以看一下c庫程式的**,這裡以uclibc為例.

int printf(const char * __restrict format, ...)

printf支援字串格式化輸出,具體引數處理這裡不提.可以看到printf()呼叫了

vfprintf(),vfprintf()第乙個引數是stdout是標準輸出裝置.標準輸出裝置是個結構體,

最重要的成員就是他的描述符,其值為1.

跟進vfprintf()函式看,裡面是複雜的引數處理,因為printf()的引數形式很靈活,

所以在vfprintf()裡面要對傳進來的引數進行解析處理,形成最終的輸出格式.有興趣的

可以看一下,借助這個可以讓你在乙個沒有作業系統的平台上實現你自己的printf()

函式.這樣你在裸機上調程式時輸出除錯資訊就更方便些(實際上uclinux的printk就是

這麼幹的).

vfprintf()在引數處理之後,就是輸出了,輸出呼叫的是putc(),進入putc()然後

再跟進幾層函式,發現呼叫了linux系統呼叫write()。呵呵,是的,輸出就是借助操作

系統**完成的。在write之前所有的**都是c庫的**,可以說是和平台無關的。

而涉及到具體輸出,就要呼叫作業系統提供給你的介面。系統呼叫的原理就是通過一定

手段(一般是trap陷阱)進入作業系統的核心空間,呼叫作業系統**來完成某些任務。

linux系統呼叫針對不同平台有不同的實現方式。這個以後再講。呼叫write()後,

進入核心空間,首先來到的就是sys_write(),這個函式**位於fs/read_write.c中。

一進入sys_write(),就要根據傳進來的fd描述符找到相應的file結構。對於標準輸出,

fd=1,每個程序的程序控制塊都有乙個開啟檔案的陣列。file結構就是根據fd在這個

陣列中查詢到相應的結構。找到結構後,就會呼叫file->write()來向外輸出。具體輸出

到**,就要看file結構對應的裝置驅動是什麼。一般嵌入式系統可以從串列埠將資訊輸

出,那麼file->write()最底層就是呼叫的串列埠驅動的類似transmit_char的函式。

有關linux的裝置驅動有很多書介紹,整個驅動的結構很複雜,我這裡也沒必要提了.

至於終端裝置怎樣掛在驅動佇列裡面,怎麼根據標準輸出的描述符找到相應的驅動結構

有興趣的莊printf()函式看,裡面是複雜的引數處理,因為printf()的引數形式很靈活,

所以在vfprintf()裡面要對傳進來的引數進行解析處理,形成最終的輸出格式.有興趣的

可以看一下,借助這個可以讓你在乙個沒有作業系統的平台上實現你自己的printf()

函式.這樣你在裸機上調程式時輸出除錯資訊就更方便些(實際上uclinux的printk就是

這麼幹的).

vfprintf()在引數處理之後,就是輸出了,輸出呼叫的是putc(),進入putc()然後

再跟進幾層函式,發現呼叫了linux系統呼叫write()。呵呵,是的,輸出就是借助操作

系統**完成的。在write之前所有的**都是c庫的**,可以說是和平台無關的。

而涉及到具體輸出,就要呼叫作業系統提供給你的介面。系統呼叫的原理就是通過一定

手段(一般是trap陷阱)進入作業系統的核心空間,呼叫作業系統**來完成某些任務。

linux系統呼叫針對不同平台有不同的實現方式。這個以後再講。呼叫write()後,

進入核心空間,首先來到的就是sys_write(),這個函式**位於fs/read_write.c中。

一進入sys_write(),就要根據傳進來的fd描述符找到相應的file結構。對於標準輸出,

fd=1,每個程序的程序控制塊都有乙個開啟檔案的陣列。file結構就是根據fd在這個

陣列中查詢到相應的結構。找到結構後,就會呼叫file->write()來向外輸出。具體輸出

到**,就要看file結構對應的裝置驅動是什麼。一般嵌入式系統可以從串列埠將資訊輸

出,那麼file->write()最底層就是呼叫的串列埠驅動的類似transmit_char的函式。

有關linux的裝置驅動有很多書介紹,整個驅動的結構很複雜,我這裡也沒必要提了.

至於終端裝置怎樣掛在驅動佇列裡面,怎麼根據標準輸出的描述符找到相應的驅動結構

有興趣的請查閱相關資料.--

手段(一般是trap陷阱)進入作業系統的核心空間,呼叫作業系統**來完成某些任務。

linux系統呼叫針對不同平台有不同的實現方式。這個以後再講。呼叫write()後,

進入核心空間,首先來到的就是sys_write(),這個函式**位於fs/read_write.c中。

一進入sys_write(),就要根據傳進來的fd描述符找到相應的file結構。對於標準輸出,

fd=1,每個程序的程序控制塊都有乙個開啟檔案的陣列。file結構就是根據fd在這個

陣列中查詢到相應的結構。找到結構後,就會呼叫file->write()來向外輸出。具體輸出

到**,就要看file結構對應的裝置驅動是什麼。一般嵌入式系統可以從串列埠將資訊輸

出,那麼file->write()最底層就是呼叫的串列埠驅動的類似transmit_char的函式。

有關linux的裝置驅動有很多書介紹,整個驅動的結構很複雜,我這裡也沒必要提了.

至於終端裝置怎樣掛在驅動佇列裡面,怎麼根據標準輸出的描述符找到相應的驅動結構

有興趣的請查閱相關資料.

printf 標準輸出

root localhost echo 123456 123456 root localhost echo 1 2 3 4 5 6 按照原格式輸出12 3456 root localhost printf 1 2 3 4 5 6 只輸出了乙個符號,沒有標稱輸出型別 1 root localhost ...

標準輸出printf與標準輸入scanf

一 標準輸出printf 標頭檔案 stdio.h 原型 int printf const char format,引數 format 格式控制字串 可變引數列表 返回值 輸出字元的數量。注意點 對於標準輸出printf,我們需要注意的是返回值,很多人會忽略返回值的型別和代表的含義。二 標準輸入sc...

C scanf和printf 輸出整數

學過c語言的讀者,對scanf函式和printf函式應該都不陌生,在c語言中最常見的輸入輸出就是用的這兩個函式,同樣在c 中也可以使用這兩個函式進行輸入和輸出,但是在c 中,普遍使用的是cin和cout函式。一般格式是 scanf 格式控制,輸出表列 案例 使用scanf函式輸入乙個整數。inclu...