7.9支持整数的格式化

本文介绍了printf()和sprintf()在C语言中的区别,重点在于printf()直接输出到控制台,而sprintf()将格式化字符串的结果保存到字符数组以便后续操作。还讨论了如何使用kernel_sprintf和kernel_vsprintf进行4进制整数的格式化转换。
摘要由CSDN通过智能技术生成

7.9支持整数的格式化

printf()和sprintf()区别

printf() 函数有以下特点:

  • 支持格式化字符串,可以按照一定的格式输出不同类型的数据;
  • 输出结果直接显示在控制台上,不需要使用其他的输出语句;
  • 输出结果无法保存到变量中,只能直接显示在控制台上。

例如:

#include <stdio.h>
 
int main() {
    int num = 123;
    float pi = 3.14159;
    char str[] = "Hello, world!";
    printf("The number is %d, the pi is %.2f, and the string is %s.\n", num, pi, str);
    return 0;
}

sprintf() 函数有以下特点:

  • 支持格式化字符串,可以按照一定的格式输出不同类型的数据;
  • 输出结果保存到字符数组中,可以被用于输出或者存储;
  • 输出结果不会直接显示在控制台上,需要使用其他的输出语句输出。

例如:

#include <stdio.h>
 
int main() {
    int num = 123;
    float pi = 3.14159;
    char str[50];
    sprintf(str, "The number is %d, the pi is %.2f.", num, pi);
    printf("%s\n", str);
    return 0;
}

从上面的例子可以看出,sprintf() 函数可以将格式化字符串的输出结果保存到字符数组中,并且可以通过其他的输出语句输出这个字符数组。

格式化字符串到缓存中

void kernel_sprintf(char * buffer, const char * fmt, ...) {
    va_list args;

    va_start(args, fmt);
    kernel_vsprintf(buffer, fmt, args);
    va_end(args);
}

对之前的kernel_vsprintf(char * buffer, const char * fmt, va_list args)函数添加代码,使其能够格式化4种进制的整数

void kernel_vsprintf(char * buffer, const char * fmt, va_list args) {
    enum {NORMAL, READ_FMT} state = NORMAL;
    char ch;
    char * curr = buffer;
    while ((ch = *fmt++)) {
        switch (state) {
            // 普通字符
            case NORMAL:
                if (ch == '%') {
                    state = READ_FMT;
                } else {
                    *curr++ = ch;
                }
                break;
            // 格式化控制字符,只支持部分
            case READ_FMT:
                if (ch == 'd') { //需要把10进制的数字格式化为字符串
                    int num = va_arg(args, int);
                    kernel_itoa(curr, num, 10);
                    curr += kernel_strlen(curr);
                } else if (ch == 'x') {//需要把16进制的数字格式化为字符串
                    int num = va_arg(args, int);
                    kernel_itoa(curr, num, 16);
                    curr += kernel_strlen(curr);
                } else if (ch == 'c') {
                    char c = va_arg(args, int);
                    *curr++ = c;
                } else if (ch == 's') {
                    const char * str = va_arg(args, char *);
                    int len = kernel_strlen(str);
                    while (len--) {
                        *curr++ = *str++;
                    }
                }
                state = NORMAL;
                break;
        }
    }
}

将int转化为字符串函数

void kernel_itoa(char * buf, int num, int base) {
    // 转换字符索引[-15, -14, ...-1, 0, 1, ...., 14, 15]
    static const char * num2ch = {"FEDCBA9876543210123456789ABCDEF"}; //因为可能有负数所以这样设计
    char * p = buf;
    int old_num = num;

    // 仅支持部分进制
    if ((base != 2) && (base != 8) && (base != 10) && (base != 16)) {
        *p = '\0';
        return;
    } //只允许这4种进制,但是我们只写了10进制和16进制,但是底下代码都通用

    // 只支持十进制负数
    int signed_num = 0;//最后逆序,如果是负数(10进制的负数)则需要逆序,需要跳过那个符号
    if ((num < 0) && (base == 10)) {
        *p++ = '-';
        signed_num = 1;
    }

    if (signed_num) {
        do {
            char ch = num2ch[num % base + 15];
            *p++ = ch;
            num /= base;
        } while (num);
    } else {
        uint32_t u_num = (uint32_t)num;
        do {
            char ch = num2ch[u_num % base + 15];
            *p++ = ch;
            u_num /= base;
        } while (u_num);
    }
    *p-- = '\0'; //最后加这个自己没有搞清楚

    // 将转换结果逆序,生成最终的结果
    char * start = (!signed_num) ? buf : buf + 1;
    while (start < p) {
        char ch = *start;
        *start = *p;
        *p-- = ch;
        start++;
    } //利用双指针逆序
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值