日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

printf家族探秘

發布時間:2023/12/13 综合教程 35 生活家
生活随笔 收集整理的這篇文章主要介紹了 printf家族探秘 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

有一個函數,是我們從學習c語言就開始的第一天就接觸的,那就是printf函數,可是這個家族的函數,帶給我們的便利卻不是一點半點,所以寫一篇用法總結。

1.printf函數

格式化輸出,可以輸出八進制,十進制,十六進制,可以輸出字符串,%p輸出地址。基本的東西就不在贅述了。

printf是有返回值的,只是一般我們用不到。printf()函數也有一個返回值,它返回所打印的字符的數目。如果有輸出錯誤,那么printf()會返回一個負數(printf( ) 的一些老版本會有不同的返回值)。

*號符,在printf函數中有著很強的格式化作用,如同linux中一樣,* 代表任意匹配。

再看一個格式化輸出十六進制的例子:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int main(void)
{
    unsigned int a=0x1;
    printf("%#010x",a);
    return 0;
}

在編程中經常會打印地址,而一般要求打印8個字節,而字節前導我們不希望使用空格而是使用前導0來填充,就可以使用上面的寫法。

# 號:使用格式說明的可選形式,#o 打印的則以0(零)開始,八進制,#x或者#X,則以0x或者0X開始,十六進制。

0(零):對于所有數字格式,用前導零填充而不是空格。如果出現 - 標志或者指定了精度(對于整數)則忽略該標志。

那么%#010x:就表示:以十六進制輸出,輸出長度一共為10,前導用0填充而不是空格。由于#x的作用占用了兩個位置,因為要輸出0x,所以還剩下8個位置,這樣就指定輸出了十六進制8個字節長度的數據。

如果這樣覺得不好閱讀,可以不使用#,直接手動書寫0x前綴,指定寬度為8,前導0即可:如:

這是printf函數的常用方法,但是正真重要的,還是在于可變參數及其家族的變種函數。

2.fprintf函數

專注于文件操作的file printf。文件輸出,其實是往文件中寫內容,如同printf函數一樣,雖然說它是輸出函數,但實質上往輸出流寫數據。fprintf聚集了printf家族的傳統,可以格式化寫文件:

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    float imag[10];
    float j=0;
    FILE *fp;
    for(int i=0;i<10;i++,j=j+0.2)
    {
        imag[i]=1.0+j;
        
    }


    if((fp=fopen("test.txt","w+"))==NULL)
    {
        printf("err
");
        fflush(stdout);
        getchar();
        exit(1);
    }
    fprintf(fp,"%s","imag[]={");
    for(int i=0;i<10;i++)
        fprintf(fp," %.4f,",imag[i]);
    fprintf(fp,"%c",'}');
    fclose(fp);
    return 0;
}

輸出文件:

fopen一個函數,使用w+的方式表示,打開一個文件,可以進行更新(讀取和寫入),如果該文件存在,就將其長度變為0,如果不存在則先創建之。

int fprintf( FILE *stream, const char * restrict format , ...);

按照format格式輸出到stream。其實,在linux學習中,我們知道一切皆文件,這個FILE指針,是可以映射到標準輸出的,即:printf(...)=fprintf(stdout,...).

3.sprintf

這個函數用得非常多,也非常重要,務必掌握。

作為printf家族成員,自然printf自帶的格式化操作它都具有。sprintf主要用于把格式化輸出寫到指定字符數組中。

先看基礎用法:

通過下面的例子了解sprintf的原理:

可以看到,sprintf把十進制數108放在字符數組buf中,但是存放的原理是,將十進制數的每一位變成字符存放在buf數組中,49對應ASCII字符1,48對應0,56對應8.這樣之后,我們就可以預估計buf數組給多大空間合適。

sprintf可以很方便的格式化類型放在數組中,我們再看一個例子:

現在試想一個問題,我們經常編程的時候想要實現中文和英文的同時保存,但是,我們怎么以除了直接初始化的方式來執行英文和中文的鏈接呢?舉例說明一下這個問題,我們想得到一個字符串,包含中文和英文,例如上面的hi,你好。我們可以這樣初始化:char str[40]="hi,你好";但是,如果我們的中文,需要由其他地方給出呢?我們怎么做到拼接字符串?我們應該知道,中文所占字節一定是大于一個字節的,根據文本編碼,對應2-4個字節(這個要注意哦)。比如現在給你兩個字符串,一個是英文的,一個是中文的,你怎么把它拼接到一起?當然,庫函數提供 了這樣拼接功能的函數,可是,我們的sprintf也可以做到,而又因為sprintf支持各種格式,所以它使用是最頻繁的,如上面例子呈現的那樣。

返回值

返回寫入buffer 的字符數,出錯則返回負數。
sprintf 返回以format為格式argument為內容組成的結果被寫入buffer 的字節數,結束字符‘’不計入內。即,如果“Hello”被寫入空間足夠大的buffer后,函數sprintf 返回5

sprintf函數等同于fprintf,除了輸出被寫入一個數組(由參數s指定),而不是一個流。 空字符()寫在寫入的字符的末尾; 它不計入返回值的一部分。 如果復制發生在重疊的對象之間,行為是未定義的。

那么我們試試違規操作呢?

可以看到,sprintf對溢出是沒有保護的,上面例子,str至少應該4個字節,就因為這樣,才有了下面的snprintf函數。

3.1 snprintf

這個函數就是在sprintf的基礎上增加了一點內容。

函數snprintf()和vsnprintf()不寫入超出字節(包括終止空字節(' 0'))。 如果由于此限制導致輸出被截斷,那么返回值是如果有足夠的空間可用,則該字符數將被寫入最終字符串(不包括終止空字節)。 因此,返回值大小比指定的n更大或者相等,意味著輸出被截斷。

還是上代碼來看,因為sprintf會因為使用不當造成內存溢出,而snprintf則不會:

#include <stdio.h>
#include <string.h>

int main()
{
    char str[5];
    int ret = snprintf(str, 3, "%s", "abcdefg");
    printf("%d
", ret);
    printf("%s
", str);
    return 0;
}

linux下運行:

vs2017運行:

gcc for Windows:

看來和編譯器有點關系呀,不過我們學習以c標準的為基準。

snprintf函數等同于fprintf,除了輸出被寫入一個數組(由參數s指定)而不是一個流。 如果n為零,則不寫任何內容,
并且s可能是空指針。 否則超出n-1的輸出字符丟棄而不是寫入數組(這就是比sprintf安全的地方了),并且空字符寫入實際寫入數組的字符的末尾。 如果復制發生在重疊的對象之間,行為是未定義的。

snprintf函數返回已寫入的字符數,n已經足夠大,不計算終止空字符,如果發生編碼錯誤返回負值。 因此,終止的輸出已經被當且僅當返回的值為非負數且小于n時才完全寫入。
見了c標準之后,可以知道,我們的gcc for Windows是和vc6.0一樣的輸入,這樣其實是沒有依照c99標準的,故不再分析這樣編譯器的輸出。

那么在現在的基礎上來分析上面的代碼:

指定n=3,輸出最多n-1個,因為snprintf需要給我們一個結尾,故只有ab被寫入,返回值,是不包含結尾的應該輸入的大小,這里是7。這證明了我們的字符有7個(不包含)需要輸出,所以要想全部輸出,我們應該指定n=8.

snprintf比sprintf安全,有了溢出保護,建議使用。

總結一下就是:snprintf有溢出保護,就算你給超出空間的內容也不會出現溢出錯誤,會被snprintf截斷。輸入的n,代表的是你想要格式化輸出到 s指針指向的空間的內容加上1,通俗一點的意思就是,你想格式化輸出7個字節到 s 指針指向的空間,那么你的 n就應該指定為8,因為snprintf只會傳遞n-1個字符過去,它要保留一個結尾.它的返回值,如果空間足夠,沒有發生截斷的情況下,返回寫入字符的個數,不包含結尾,如果發生截斷,返回的是應該寫入的長度,不包含結尾,所以不管截斷不截斷,返回值的數學值都是相同的,只是代表的意義不同,如果寫入發生錯誤,返回負數。

4.vsprintf

#include<stdio.h>
#include <stdio.h>
#include <stdarg.h>
/*
    在LCD_printf中應用
    ※※※

*/

char buffer[30];
int vspfunc(char *format, ...)
{
   va_list aptr;
   int ret;

   va_start(aptr, format);
   ret = vsprintf(buffer, format, aptr);
   va_end(aptr);

   return(ret);
}

int main()
{
   int i = 1115;
   float f = 27.0;
   char str[10] = "world";

   vspfunc("hello %d %f %s", i, f, str);
   printf("%s", buffer); 
   return(0);
}

4.1 vsnprintf

和snprintf的功能對于sprintf一樣,vsnprintf也是處于這樣的原因成為升級版的vsprintf

總結

以上是生活随笔為你收集整理的printf家族探秘的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。