在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > glibc中的printf如何輸出到串口

            glibc中的printf如何輸出到串口

            作者: 時(shí)間:2016-11-22 來(lái)源:網(wǎng)絡(luò) 收藏
            內(nèi)核版本:2.6.14

            glibc版本:2.3.6

            本文引用地址:http://www.biyoush.com/article/201611/319993.htm

            CPU平臺(tái):arm

            printf輸出不一定是串口,也可以是LCD,甚至是文件等,這里僅以輸出到串口為例。本文分析了printf和文件描述符0、1和2以及stdout、stdin和stderr的關(guān)系,通過這篇文章可以知道文件描述符0、1和2為什么對(duì)應(yīng)著stdout、stdin和stderr,因?yàn)間libc就是這么定義的?。?!

            首先看glibc中printf函數(shù)的定義(glibc-2.3.6/stdio-common/printf.c):

            [plain]view plaincopy
            print?
            1. #undefprintf
            2. /*WriteformattedoutputtostdoutfromtheformatstringFORMAT.*/
            3. /*VARARGS1*/
            4. int
            5. printf(constchar*format,...)
            6. {
            7. va_listarg;
            8. intdone;
            9. va_start(arg,format);
            10. done=vfprintf(stdout,format,arg);//主要是這個(gè)函數(shù)
            11. va_end(arg);
            12. returndone;
            13. }
            14. #undef_IO_printf
            15. /*Thisisforlibg++.*/
            16. strong_alias(printf,_IO_printf);

            strong_alias,即取別名。網(wǎng)上有人提及這個(gè)strong alias好像是為了防止c庫(kù)符號(hào)被其他庫(kù)符號(hào)覆蓋掉而使用的,如果printf被覆蓋了,還有_IO_printf可以用。跟蹤vfprintf函數(shù)(),我們先給出該函數(shù)的聲明,如下(glibc-2.3.6/libio/stdio.h):

            [plain]view plaincopy
            print?
            1. externintvfprintf(FILE*__restrict__s,__constchar*__restrict__format,
            2. _G_va_list__arg);
            printf函數(shù)是通過vfprintf將format輸出到stdout文件中,stdout是(FILE *)類型。stdout的定義如下(glibc-2.3.6/libio/stdio.h),順被也給出stdin和stderr的定義:

            [plain]view plaincopy
            print?
            1. /*Standardstreams.*/
            2. externstruct_IO_FILE*stdin;/*Standardinputstream.*/
            3. externstruct_IO_FILE*stdout;/*Standardoutputstream.*/
            4. externstruct_IO_FILE*stderr;/*Standarderroroutputstream.*/
            5. /*C89/C99saytheyremacros.Makethemhappy.*/
            6. #definestdinstdin
            7. #definestdoutstdout
            8. #definestderrstderr
            繼續(xù)跟蹤stdout(glibc-2.3.6/libio/stdio.c):

            [plain]view plaincopy
            print?
            1. _IO_FILE*stdin=(FILE*)&_IO_2_1_stdin_;
            2. _IO_FILE*stdout=(FILE*)&_IO_2_1_stdout_;
            3. _IO_FILE*stderr=(FILE*)&_IO_2_1_stderr_;
            在繼續(xù)分析_IO_2_1_stdout_之前,我們先看一下_IO_FILE(FILE和_IO_FILE是一回事,#define FILE _IO_FILE)的定義(glibc-2.3.6/libio/libio.h):

            [plain]view plaincopy
            print?
            1. struct_IO_FILE{
            2. int_flags;/*High-orderwordis_IO_MAGIC;restisflags.*/
            3. #define_IO_file_flags_flags
            4. /*ThefollowingpointerscorrespondtotheC++streambufprotocol.*/
            5. /*Note:Tkusesthe_IO_read_ptrand_IO_read_endfieldsdirectly.*/
            6. char*_IO_read_ptr;/*Currentreadpointer*/
            7. char*_IO_read_end;/*Endofgetarea.*/
            8. char*_IO_read_base;/*Startofputback+getarea.*/
            9. char*_IO_write_base;/*Startofputarea.*/
            10. char*_IO_write_ptr;/*Currentputpointer.*/
            11. char*_IO_write_end;/*Endofputarea.*/
            12. char*_IO_buf_base;/*Startofreservearea.*/
            13. char*_IO_buf_end;/*Endofreservearea.*/
            14. /*Thefollowingfieldsareusedtosupportbackingupandundo.*/
            15. char*_IO_save_base;/*Pointertostartofnon-currentgetarea.*/
            16. char*_IO_backup_base;/*Pointertofirstvalidcharacterofbackuparea*/
            17. char*_IO_save_end;/*Pointertoendofnon-currentgetarea.*/
            18. struct_IO_marker*_markers;
            19. struct_IO_FILE*_chain;
            20. int_fileno;//這個(gè)就是linux內(nèi)核中文件描述符fd
            21. #if0
            22. int_blksize;
            23. #else
            24. int_flags2;
            25. #endif
            26. _IO_off_t_old_offset;/*Thisusedtobe_offsetbutitstoosmall.*/
            27. #define__HAVE_COLUMN/*temporary*/
            28. /*1+columnnumberofpbase();0isunknown.*/
            29. unsignedshort_cur_column;
            30. signedchar_vtable_offset;
            31. char_shortbuf[1];
            32. /*char*_save_gptr;char*_save_egptr;*/
            33. _IO_lock_t*_lock;
            34. #ifdef_IO_USE_OLD_IO_FILE
            35. };
            36. struct_IO_FILE_plus
            37. {
            38. _IO_FILEfile;
            39. conststruct_IO_jump_t*vtable;//IO函數(shù)跳轉(zhuǎn)表
            40. };

            下面我們看看_IO_2_1_stdout_的定義(glibc-2.3.6/libio/stdfiles.c),順便給出_IO_2_1_stdin_和_IO_2_1_stderr_的定義:

            [plain]view plaincopy
            print?
            1. #defineDEF_STDFILE(NAME,FD,CHAIN,FLAGS)
            2. struct_IO_FILE_plusNAME
            3. ={FILEBUF_LITERAL(CHAIN,FLAGS,FD,NULL),
            4. &_IO_file_jumps};
            5. DEF_STDFILE(_IO_2_1_stdin_,0,0,_IO_NO_WRITES);
            6. DEF_STDFILE(_IO_2_1_stdout_,1,&_IO_2_1_stdin_,_IO_NO_READS);
            7. DEF_STDFILE(_IO_2_1_stderr_,2,&_IO_2_1_stdout_,_IO_NO_READS+_IO_UNBUFFERED);

            從這里我們可以看到,_IO_2_1_stdout_的FD = 0、_IO_2_1_stdin_的FD = 1、_IO_2_1_stderr_的FD = 2。FILEBUF_LITERAL用于初始化_IO_FILE,定義如下(glibc-2.3.6/libio/libioP.h):

            [plain]view plaincopy
            print?
            1. #defineFILEBUF_LITERAL(CHAIN,FLAGS,FD,WDP)
            2. {_IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS,
            3. 0,0,0,0,0,0,0,0,0,0,0,0,(_IO_FILE*)CHAIN,FD,
            4. 0,_IO_pos_BAD,0,0,{0},0,_IO_pos_BAD,
            5. 0}
            其中,F(xiàn)D賦值給了_fileno。我們回到vfprintf的分析,vfprintf的具體實(shí)現(xiàn)本文就不詳細(xì)講解,主要原理是格式化字符串,最后將字符串輸出到文件中,也就是stdout中。至于如何輸出,則和_IO_file_jumps關(guān)系密切,_IO_file_jumps的定義如下:

            [plain]view plaincopy
            print?
            1. conststruct_IO_jump_t_IO_file_jumps=
            2. {
            3. JUMP_INIT_DUMMY,
            4. JUMP_INIT(finish,INTUSE(_IO_file_finish)),
            5. JUMP_INIT(overflow,INTUSE(_IO_file_overflow)),
            6. JUMP_INIT(underflow,INTUSE(_IO_file_underflow)),
            7. JUMP_INIT(uflow,INTUSE(_IO_default_uflow)),
            8. JUMP_INIT(pbackfail,INTUSE(_IO_default_pbackfail)),
            9. JUMP_INIT(xsputn,INTUSE(_IO_file_xsputn)),
            10. JUMP_INIT(xsgetn,INTUSE(_IO_file_xsgetn)),
            11. JUMP_INIT(seekoff,_IO_new_file_seekoff),
            12. JUMP_INIT(seekpos,_IO_default_seekpos),
            13. JUMP_INIT(setbuf,_IO_new_file_setbuf),
            14. JUMP_INIT(sync,_IO_new_file_sync),
            15. JUMP_INIT(doallocate,INTUSE(_IO_file_doallocate)),
            16. JUMP_INIT(read,INTUSE(_IO_file_read)),
            17. JUMP_INIT(write,_IO_new_file_write),
            18. JUMP_INIT(seek,INTUSE(_IO_file_seek)),
            19. JUMP_INIT(close,INTUSE(_IO_file_close)),
            20. JUMP_INIT(stat,INTUSE(_IO_file_stat)),
            21. JUMP_INIT(showmanyc,_IO_default_showmanyc),
            22. JUMP_INIT(imbue,_IO_default_imbue)
            23. };
            至于怎么跳轉(zhuǎn)到這些函數(shù),以及如何跳轉(zhuǎn)到linux內(nèi)核,由于涉及到glibc的一些細(xì)節(jié),這里簡(jiǎn)單介紹一下進(jìn)入內(nèi)核后的情況:進(jìn)入linux內(nèi)核后,調(diào)用write(),在write之前所有的代碼都是C庫(kù)的代碼,可以說(shuō)是和平臺(tái)無(wú)關(guān)的。而涉及到具體輸出,就要調(diào)用操作系統(tǒng)提供給的接口。調(diào)用write()后,通過系統(tǒng)調(diào)用進(jìn)入內(nèi)核空間,首先是sys_write(),這個(gè)函數(shù)代碼位于fs/read_write.c中。一進(jìn)入sys_write(),就要根據(jù)傳進(jìn)來(lái)的fd描述符找到相應(yīng)的file結(jié)構(gòu)。對(duì)于標(biāo)準(zhǔn)輸出,fd= 1,每個(gè)進(jìn)程的進(jìn)程控制塊都有一個(gè)打開文件的數(shù)組files。file結(jié)構(gòu)就是根據(jù)fd在這個(gè)數(shù)組中查找到相應(yīng)的結(jié)構(gòu)。找到結(jié)構(gòu)后,就會(huì)調(diào)用file->write()來(lái)向外輸出。具體輸出到哪里,就要看file結(jié)構(gòu)對(duì)應(yīng)的設(shè)備驅(qū)動(dòng)是什么。

            通過本文可以理解:文件描述符0、1和2和stdout、stdin和stderr對(duì)應(yīng),如果要修改linux內(nèi)核中文件描述符相關(guān)代碼,一定要注意文件描述符0、1和2的分配和回收,否則會(huì)導(dǎo)致終端沒有輸出信息,也無(wú)法和內(nèi)核輸入信息。



            關(guān)鍵詞: glibcprintf輸出串

            評(píng)論


            技術(shù)專區(qū)

            關(guān)閉