printf函数与缓冲区

在linux下,printf输出到控制台经历了app->libc(stdio.h)->syscall->console驱动
 
下面是<<linux内核完全注释>>一书中的一段描述:
0
继续看下write函数的实现:
以下是write()函数的基本定义:
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
// ssize_t是一个有符号整数类型,通常用来表示读取或者写入的字节数。c中ssize_t通常被定义为typedef long int ssize_t,也就是long int类型来表示
  • fd:表示要写入的文件描述符。在UNIX系统中,标准输出流(终端屏幕显示)的文件描述符是1,标准错误流的文件描述符是2,标准输入流的文件描述符是0。
  • buf:指向要写入数据的缓冲区的指针。
  • count:表示要写入的字节数。
write()函数会尝试将count个字节的数据从buf指向的缓冲区写入到文件描述符fd所代表的文件中。如果成功,它会返回实际写入的字节数,如果失败,则返回-1,并设置全局变量errno来标识具体的错误原因。
 
write函数使用示例:
当使用write()函数将数据写入到文件中时,需要首先使用open()函数打开文件,并获取文件描述符,然后使用write()函数向文件描述符所代表的文件中写入数据。
#include <unistd.h>
#include <fcntl.h>

int main() {
    int fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); // 打开文件以便写入
    if (fd == -1) {
        // 处理文件打开失败的情况
        return 1;
    }

    const char *str = "Hello, world!\n";
    ssize_t bytes_written = write(fd, str, strlen(str)); // 将字符串写入到文件
    if (bytes_written == -1) {
        // 处理写入失败的情况
    }

    close(fd); // 关闭文件
    return 0;
}
在上述代码中:
使用open()函数打开output.txt文件,如果文件不存在则创建,O_WRONLY表示以只写方式打开文件,O_CREAT表示如果文件不存在则创建,O_TRUNC表示清空文件内容。
在成功打开文件后,使用write()函数将字符串"Hello, world!\n"写入到文件中。最后,使用close()函数关闭文件描述符
当运行上述代码时,字符串将会被写入到名为output.txt的文件中。
 
write函数会系统调用到内核,内核uart驱动将其在串口输出,也就是我们看到的屏幕打印。
 
延伸出来介绍下android c++打印:
#include LOG_TAG
#undef LOG_TAG
#endif
 
#define LOG_TAG "lethe_DEBUG"
#include <android/log.h>    // 在此处等价于 #include<utils/Log.h>
// 在使用可变参数列表的宏时,如果可变参数列表为空,那么在宏展开时可能会导致语法错误。为了避免这种情况,##操作符可以用于将可变参数列表与前面的标识符分开,以确保在没有可变参数时不会产生语法错误。
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,## __VA_ARGS__)
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, ## __VA_ARGS__)
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, ## __VA_ARGS__)
 
fun()
{
        ALOGE("debug log");
}
以ALOGE打印为例,ALOGE是android平台上用于打印错误级别日志信息的宏定义。在android源码中,ALOGE通常被定义为__android_log_print函数的一个简化形式
 
知识点一、...和##和__VA_ARGS__
__VA_ARGS__是c语言中的一个特殊宏,用于可变参数列表。在C语言中,有一类宏称为可变参数宏(variadic macros),允许在宏展开时接受不定数量的参数。而
__VA_ARGS__就是用于代表这个可变参数列表的占位符。
##是一种处理器操作符,称为连接操作符或者粘贴操作符,它的作用是将两个标识符连接成一个标识符,下面举例:
#define PRINT_COORD(x, y) printf("Coordinates: " #x ", " #y "\n");
PRINT_COORD(10, 20); // 打印出 "Coordinates: 10, 20"。
在c语言中,...是可变参数列表。在宏定义中,...表示可变参数的部分,即宏可以接受任何数量的参数
 
缓冲区:
全缓冲:写磁盘文件一般是全缓冲
还可以使用fflush函数,它可以将缓冲区中的内容写入到磁盘中(终端驱动设备表示丢弃缓冲区的数据)。所以将fwrite下面一行的注释去掉后,就可以发现,写入之后,就可以直接在文件中看到内容
#include<stdio.h> #include<unistd.h> int main(void) { /*以可读可写的方式打开*/ FILE *fp = fopen("./test.txt","w+"); if(NULL == fp) { perror("open file failed"); return -1; } /*写入内容*/ char buf[] = "--------------------\n"; fwrite(buf,sizeof(char),sizeof(buf),fp); //fflush(fp); /*sleep一段时间,以便观察*/ sleep(20); fclose(fp); return 0; }
行缓冲:行缓冲指的是当遇到换行符时,或者缓冲区已经满了(一般1024字节),标准I/O库执行I/O操作。printf执行完了之后,内容并没有马上输出到终端,而是在程序运行完之后才输出。举例子如下:
#include<stdio.h> #include<unistd.h> int main(void) { printf("-----------------"); sleep(10); return 0; }
无缓冲:stderr是无缓冲
#include<stdio.h> #include<unistd.h> int main(void) { fprintf(stderr,"wechat:shouwangxiansheng"); sleep(10); return 0; }
 
疑问解析
android中的打印为啥不会出现不出现打印的情况呢?
logd守护进程是Android系统中负责接收、过滤和处理日志信息的组件之一。它在内部使用了缓冲机制来管理和处理日志数据。
具体来说,logd守护进程的缓冲机制包括以下几个方面:
  1. 日志缓冲区:logd维护了多个日志缓冲区,用于存储不同级别的日志信息。这些缓冲区以环形缓冲区的形式组织,可以容纳一定数量的日志条目。
  2. 缓冲区分级:logd将不同级别的日志信息分别存储在不同的缓冲区中。常见的缓冲区级别包括Main、System、Events等,每个缓冲区都有对应的大小限制。
  3. 日志条目格式化:当日志信息通过__android_log_printf函数或其他方式提交给logd时,logd会将其格式化为一定的结构体格式,并将该结构体放入相应的缓冲区中。
  4. 缓冲区切换:当一个缓冲区已满时,logd会自动切换到下一个可用的缓冲区。这样可以确保日志信息的连续记录,并且不会因为缓冲区满导致丢失日志。
  5. 日志写入:logd会定期将缓冲区中的日志信息写入到日志文件中,以便长期存储和查看。写入操作可以由定时触发、缓冲区满触发或手动触发。
需要注意的是,以上是对logd守护进程缓冲机制的一般描述,具体的实现可能会因Android系统版本和配置而有所不同。此外,Android系统还提供了一些配置选项和接口,允许开发者进行一定的定制和操作,以满足特定需求和场景下的日志输出要求。
logd守护进程的缓冲机制并不是严格的行缓冲方式。虽然logd会将日志信息存储在缓冲区中,但它并不是按照每行进行缓冲和刷新的。
具体来说,当应用程序调用__android_log_printf函数或其他方式提交日志信息给logd时,logd将接收到的日志信息格式化为一定的结构体,并将该结构体放入相应的日志缓冲区中。这里的缓冲区是以环形缓冲区的形式组织的,可以容纳一定数量的日志条目。
logd并不会立即将日志缓冲区中的内容写入到日志文件中,而是在一定的条件下触发写入操作。这些条件包括缓冲区大小达到上限、定时触发、系统事件触发等。因此,logd的缓冲机制更倾向于批量写入而非每次都进行行缓冲和刷新操作。
 
总之,android日志系统并不是简单的行缓冲方式,具体不用去深究。
也给到我们一种跟性能有关的方法,kill -9 logd
 
 
posted @ 2024-03-10 16:33  lethe1203  阅读(109)  评论(0编辑  收藏  举报