我正在尝试在微内核 seL4 上实现一个最小的 scanf
,仅具有读取字符串的功能。因此,我试图通过阅读 musllibc 来找到一些线索实现其 scanf
。
我发现,在 stdio.h
,stdin
映射到 __stdinp
:
#define stdin __stdinp
#define stdout __stdoutp
#define stderr __stderrp
但是,我不明白 __stdinp
来自哪里。
例如,musllibc实现scanf
通过调用函数vscanf
。 vscanf.c
内容如下:
#include <stdio.h>
#include <stdarg.h>
#include "libc.h"
int vscanf(const char *restrict fmt, va_list ap)
{
return vfscanf(stdin, fmt, ap);
}
weak_alias(vscanf,__isoc99_vscanf);
由于我使用的是 MacOS,所以这里的 stdin
映射到 __stdinp
;据我所知。 stdin
接下来如何工作,以及它如何引导到实际的 stdin 端口以读取标准输入?
最佳答案
我认为您看错了地方,即您做出了错误的假设:
#include <stdio.h>
这行看起来可能包含苹果的 libc header stdio.h
但可以使用 -I
更改系统 header 包括搜索路径(musllibc 的 Makefile
会这样做) )。
所以苹果的stdio.h
与这段代码完全无关。
如果您深入 musllibc 存储库,您会发现他们的 stdio.h
版本文件如下所示:
/* ... */
extern FILE *const stdin;
extern FILE *const stdout;
extern FILE *const stderr;
#define stdin (stdin)
#define stdout (stdout)
#define stderr (stderr)
/* ... */
按照定义你会发现FILE *const stdin
定义在/src/stdio/stdin.c
中:
#include "stdio_impl.h"
static unsigned char buf[BUFSIZ+UNGET];
static FILE f = {
.buf = buf+UNGET,
.buf_size = sizeof buf-UNGET,
.fd = 0,
.flags = F_PERM | F_NOWR,
.read = __stdio_read,
.seek = __stdio_seek,
.close = __stdio_close,
.lock = -1,
};
FILE *const stdin = &f;
FILE *volatile __stdin_used = &f;
正如预期的那样,__stdio_read
使用 system call阅读:
#include "stdio_impl.h"
#include <sys/uio.h>
size_t __stdio_read(FILE *f, unsigned char *buf, size_t len)
{
struct iovec iov[2] = {
{ .iov_base = buf, .iov_len = len - !!f->buf_size },
{ .iov_base = f->buf, .iov_len = f->buf_size }
};
ssize_t cnt;
// the actual reading takes place here
// system call takes place here
cnt = syscall(SYS_readv, f->fd, iov, 2);
if (cnt <= 0) {
f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt);
return cnt;
}
if (cnt <= iov[0].iov_len) return cnt;
cnt -= iov[0].iov_len;
f->rpos = f->buf;
f->rend = f->buf + cnt;
if (f->buf_size) buf[len-1] = *f->rpos++;
return len;
}
系统调用提供应用程序和底层内核之间的接口(interface)。
关于c - 什么是 __stdinp?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76832533/