嵌入式Linux系统编程 — 2.3 标准I/O库:格式化I/O

目录

1 格式化I/O简介

2 格式化输出

2.1 格式化输出函数简介

2.2 格式控制字符串 format

2.3 示例程序

3 格式化输入

3.1 格式化输入简介

3.2 格式控制字符串 format

3.3 示例程序


1 格式化I/O简介

在先前示例代码中,经常使用库函数 printf() 来输出程序中的打印信息,printf() 函数能够将格式化的数据输出到标准输出设备,因此它通常被称为格式化输出函数。除了 printf(),还提供了其他几种格式化输出函数,包括 fprintf()dprintf()sprintf()snprintf()

与格式化输出相对应的是格式化输入,它允许从标准输入中获取格式化数据。格式化输入函数包括 scanf()fscanf()sscanf()

2 格式化输出

2.1 格式化输出函数简介

C 库函数提供了 5 个格式化输出函数,包括: printf()、 fprintf()、 dprintf()、 sprintf()、 snprintf(),其函数定义如下所示:

printf():将格式化的数据输出到标准输出(通常是终端或控制台)。

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

fprintf():将格式化的数据输出到指定的文件,stream 参数可以是任何有效的文件指针。

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

dprintf():直接将格式化的数据写入到指定的文件描述符 fd

int dprintf(int fd, const char *format, ...);

sprintf():将格式化的数据写入到字符数组 str 中,这通常用于字符串操作。

int sprintf(char *str, const char *format, ...);

snprintf():类似于 sprintf(),但增加了对输出缓冲区大小的限制,size 参数指定了最大可写入的字符数,包括结尾的空字符。

int snprintf(char *str, size_t size, const char *format, ...);

2.2 格式控制字符串 format

格式化输出函数中的format 参数称为格式控制字符串,顾名思义,首先它是一个字符串的形式,其次它能够控制后续变参的格式转换。格式控制字符串由两部分组成:普通字符(非%字符) 和转换说明。普通字符会进行原样输出,每个转换说明都会对应后续的一个参数,通常有几个转换说明就需要提供几个参数, 使之一一对应。如下所示:

printf("转换说明 1 转换说明 2 转换说明 3", arg1, arg2, arg3);

格式控制字符串(format )定义了输出数据的格式,包括数据类型、宽度、精度、填充字符等。格式控制字符串通常包括以下几个部分:

转换说明符(Conversion Specifier):指定要输出的数据类型,例如:

  • %d 表示十进制整数。
  • %f 表示浮点数。
  • %s 表示字符串。
  • %c 表示字符。
  • %x 或 %X 表示十六进制整数(小写或大写)。

标志(Flags):可以改变输出格式的选项,例如:

  • %- 表示左对齐。
  • %+ 表示总是显示正负号。
  • %0 表示使用零填充到指定宽度。
  • %# 表示显示八进制数的前缀 0 或十六进制数的前缀 0x 或 0X

宽度(Width):指定输出的最小字符数,如果数据不足,会用空格或指定的填充字符填充。

精度(Precision):对于浮点数,指定小数点后的位数;对于字符串,指定最大字符数。

长度修饰符(Length Modifier):指定数据的长度,例如:

  • %l 表示长整型(long int)。
  • %h 表示短整型(short int)。
  • %ll 表示长长整型(long long int)。

填充字符:如果指定了宽度,可以使用填充字符来填充输出,例如 %10s 会输出一个字符串,并且在其前后填充空格直到宽度达到10个字符。

每个转换说明都是以%字符开头,只有%和 type 字段是必须的,其余都是可选的。其格式如下所示(使用[ ]括起来的部分是可选的) :

%[flags][width][.precision][length]type

例如下面的示例输出:

printf("%d\n", 123);
//输出:123
//注释:以十进制形式输出整数123,后面跟着一个换行符。

printf("%o\n", 123);
//输出:173
//注释:将整数123转换为八进制形式并输出,后面跟着一个换行符。在八进制中,123等于173。

printf("%06d", 1000);
//输出:001000
//注释:以零填充到至少6位的宽度输出整数1000。由于1000不足6位,前面用0填充。

printf("%.8f\n", 520.1314);
//输出:520.13140000
//注释:以浮点数形式输出520.1314,精度指定为8位小数,因此输出时会显示8位小数,即使最后几位是0。

printf("%lld\n", 12345);
//输出:12345
//注释:将整数12345以long long int类型输出,lld是长度修饰符,表示长长整型(64位)。即使没有这个修饰符,大多数现代编译器也会将整型默认为int类型,但使用lld可以确保在所有编译器中都以长整型处理。

2.3 示例程序

下面的程序展示了 printf()fprintf()dprintf()sprintf()snprintf() 函数的使用。每个函数都用来输出格式化的字符串,但它们输出到的地方不同。

#include <stdio.h>

int main() {
    int number = 10;
    char str[] = "Hello, World!";
    float pi = 3.14159;

    // 使用 printf() 输出到标准输出
    printf("Standard output: %s\n", str);

    // 使用 fprintf() 输出到文件
    FILE *file = fopen("output.txt", "w");
    if (file != NULL) {
        fprintf(file, "File output: %s\n", str);
        fclose(file);
    }

    // 使用 dprintf() 输出到文件描述符
    dprintf(fileno(stdout), "Standard output descriptor: %d\n", number);

    // 使用 sprintf() 将格式化字符串存储到字符数组
    char buffer[100];
    sprintf(buffer, "Buffer output: %.2f\n", pi);
    printf("%s", buffer);

    // 使用 snprintf() 将格式化字符串存储到字符数组,限制长度
    snprintf(buffer, sizeof(buffer), "Buffer output with limit: %.2f\n", pi);
    printf("%s", buffer);

    return 0;
}
  • printf() 直接将格式化的字符串输出到标准输出(通常是控制台)。
  • fprintf() 需要一个文件指针作为第一个参数,然后将格式化的字符串写入到该文件。
  • dprintf() 类似于 fprintf(),但它使用文件描述符而不是文件指针。
  • sprintf() 将格式化的字符串存储到提供的字符数组中。需要确保数组足够大以避免溢出。
  • snprintf() 与 sprintf() 类似,但提供了一个额外的长度参数来限制写入的字符数,这有助于防止溢出。

程序运行的结果如下:

3 格式化输入

3.1 格式化输入简介

C 库函数提供了 3 个格式化输入函数,包括: scanf()、 fscanf()、 sscanf(),下面是每个函数的简要介绍:

scanf():从标准输入(通常是键盘输入)读取格式化输入。

int scanf(const char *format, ...);

fscanf():从指定的文件中读取格式化输入,文件通过 FILE 指针指定,它有两个固定参数, FILE 指针和格式控制字符串 format。

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

 sscanf():从字符串中读取格式化输入。

int sscanf(const char *str, const char *format, ...);

3.2 格式控制字符串 format

与格式化输出函数中的 format 参数格式、写法上比较相似,但也有一些区别。 format 字符串包含一个或多个转换说明,每一个转换说明都是以百分号"%"或者"%n$"开头(n 是一个十进制数字),关于"%n$"这种开头的转换说明使用的不多。

转换格式与输入类似,以%百分号开头的转换说明一般格式如下:

%[*][width][length]type
%[m][width][length]type

%*不会对转换后的结果进行存储:后面可选择性添加星号*或字母 m,如果添加了星号*,格式化输入函数会按照转换说明的指示读取输入,但是丢弃输入,意味着不需要对转换后的结果进行存储,所以也就不需要提供相应的指针参数。
%m会对转换后的结果进行存储:如果添加了 m,它只能与%s、 %c 以及%[一起使用,调用者无需分配相应的缓冲区来保存格式转换后的数据,原因在于添加了 m,这些格式化输入函数内部会自动分配足够大小的缓冲区,并将缓冲区的地址值通过与该格式转换相对应的指针参数返回出来,该指针参数应该是指向 char *变量的指针。随后,当不再需要此缓冲区时,调用者应调用 free()函数来释放此缓冲区。

3.3 示例程序

下面的程序演示了标准输入输出函数 scanf()fprintf()fscanf()sscanf() 的基本用法。

#include <stdio.h>

int main() {
    int i;
    float f;
    char s[50];
    FILE *file;

    // 使用 scanf() 从标准输入读取整数和浮点数
    printf("Enter an integer and a float: ");
    scanf("%d %f", &i, &f);
    printf("You entered: %d, %.2f\n", i, f);

    // 写入数据到 input.txt 文件
    file = fopen("input.txt", "w");
    if (file == NULL) {
        printf("Failed to open file for writing.\n");
    } else {
        fprintf(file, "fscanf test!\n");
        fclose(file);
    }

    // 读取 input.txt 文件中的数据
    file = fopen("input.txt", "r");
    if (file == NULL) {
        printf("Failed to open file for reading.\n");
    } else {
        fscanf(file, "%8s ", s);
        printf("Read from file: %s\n", s);
        fclose(file);
    }

    // 使用 sscanf() 从字符串读取数据
    sscanf("123 456.78 Hello", "%d %f %s", &i, &f, s);
    printf("Parsed: %d, %.2f, %s\n", i, f, s);

    return 0;
}

代码首先通过 scanf() 从用户那里获取一个整数和一个浮点数,并打印出来。然后写入文本到 input.txt 文件,并通过fscanf()读取这个文件的前8个字符,打印读取的内容。最后通过 sscanf() 从固定字符串中解析数据,并将结果输出。程序运行结果如下:

相关推荐

  1. Linux | 标准IO编程

    2024-06-07 15:12:08       30 阅读
  2. 嵌入24——IO

    2024-06-07 15:12:08       53 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-07 15:12:08       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-07 15:12:08       106 阅读
  3. 在Django里面运行非项目文件

    2024-06-07 15:12:08       87 阅读
  4. Python语言-面向对象

    2024-06-07 15:12:08       96 阅读

热门阅读

  1. 【无题】互联网时代,问题何去何从?

    2024-06-07 15:12:08       33 阅读
  2. 免费时间戳服务器url

    2024-06-07 15:12:08       39 阅读
  3. 如何开发地块建模

    2024-06-07 15:12:08       28 阅读
  4. 考上民办要不要去上

    2024-06-07 15:12:08       24 阅读
  5. 手机如何开启开发者选项? (小米为例)

    2024-06-07 15:12:08       68 阅读