是否可以知道有多少字节已打印到文件流(例如标准输出)?

发布于 2024-10-21 13:44:25 字数 154 浏览 0 评论 0原文

C 中的调用程序是否可以知道它已打印到文件流(例如 stdout)中的字节数,而无需实际计算和累加 printf 的返回值?

我试图实现对使用库打印的 C 程序的输出量的控制,但库不报告它们已打印的数据量。

我对通用解决方案或特定于 Unix 的解决方案感兴趣。

Is it possible for a caller program in C to know how many bytes it has printed to a file stream such as stdout without actually counting and adding up the return values of printf?

I am trying to implement control of the quantity of output of a C program which uses libraries to print, but the libraries don't report the amount of data they have printed out.

I am interested in either a general solution or a Unix-specific one.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挽手叙旧 2024-10-28 13:44:25

POSIX 特定:将 stdout 重定向到文件,在完成所有写入后刷新,然后统计文件并查看 st_size (或使用 ls > 命令)。

更新:您说您正在尝试控制程序的输出数量。 POSIX head 命令可以做到这一点。如果这不令人满意,请明确说明您的要求。

POSIX-specific: redirect stdout to a file, flush after all writing is done, then stat the file and look at st_size (or use the ls command).

Update: You say you're trying to control the quantity of output of a program. The POSIX head command will do that. If that's not satisfactory, then state your requirements clearly.

飘然心甜 2024-10-28 13:44:25

这是一个重量级的解决方案,但以下方法可以工作:

  1. 通过调用pipe()创建一个管道
  2. 生成一个子进程
  3. 在父进程中:将stdout重定向到写入端管道,并关闭读取端(和旧的 stdout
  4. 在子进程中:继续从管道的读取端读取,并将数据复制到继承的 stdout (这是原始的 stdout) -
  5. 在父级中,像往常一样继续写入 stdout (现在是管道)
  6. 使用某种形式的 IPC将计数结果从子级传达给父级。

基本上,其想法是生成一个子进程,并通过它传输所有输出,并让子进程在其通过时对所有数据进行计数。

使用的 IPC 的精确形式可能会有所不同 - 例如,共享内存(每一侧都有原子读/写)可以很好地实现数据的快速传输,但其他方法(例如套接字、更多管道等)也是可能的,并且提供更好的同步范围。

最棘手的部分是同步,即确保当子进程告诉父进程已写入了多少数据时,它已经处理了父进程所说的所有数据(例如,管道中没有剩余数据) 。这有多重要将取决于您的目标是什么 - 如果只需要一个大概的指示,那么您可能能够避免使用 IPC 共享内存而不执行任何显式同步;如果仅在最后需要总计,那么您可以从父级关闭 stdout,并让子级在收到 eof 通知时在共享内存中进行指示。

如果您需要更频繁的读取(必须准确),那么将需要更多的复杂性,但这可以通过在共享内存中使用套接字、管道甚至 condvars/semaphores/etc 设计某种协议来实现。

It's rather a heavyweight solution, but the following will work:

  1. Create a pipe by calling pipe()
  2. Spawn a child process
  3. In the parent: redirect stdout to the write-side of the pipe, and close the read side (and the old stdout)
  4. In the child: keep reading from the read side of the pipe, and copying the data to the inherited stdout (which is the original stdout) - counting it as it goes past
  5. In the parent, keep writing to stdout (which is now the pipe) as usual
  6. Use some form of IPC to communicate the result of the count from the child to the parent.

Basically the idea is to spawn a child process, and pipe all output through it, and have the child process count all the data as it goes through.

The precise form of IPC to use may vary - for example, shared memory (with atomic reads/writes on each side) would work well for fast transfer of data, but other methods (such as sockets, more pipes etc) are possible, and offer better scope for synchronisation.

The trickiest part is the synchronisation, i.e. ensuring that, at the time the child tells the parent how much data has been written, it has already processed all the data that the parent said (and there is none left in the pipe, for example). How important this is will depend on exactly what your aim is - if an approximate indication is all that's required, then you may be able to get away with using shared memory for IPC and not performing any explicit synchronisation; if the total is only required at the end then you can close stdout from the parent, and have the child indicate in the shared memory when it has received the eof notification.

If you require more frequent readouts, which must be exact, then something more copmlex will be required, but this can be achieved by designing some sort of protocol using sockets, pipes, or even condvars/semaphores/etc in the shared memory.

佞臣 2024-10-28 13:44:25

printf 返回写入的字节数。

把它们加起来。

printf returns the number of bytes written.

Add them up.

忘你却要生生世世 2024-10-28 13:44:25

不知道这有多可靠,但您可以在标准输出上使用 ftell

long int start = ftell(stdout);
printf("abcdef\n");
printf("%ld\n", ftell(stdout) - start); // >> 7

编辑
在 Ubuntu Precise 上检查了这一点:如果输出到控制台,它就不起作用,但如果它被重定向到文件,它就起作用。

$ ./a.out 
abcdef
0
$ ./a.out >tt
$ cat tt
abcdef
7
$ echo `./a.out`
abcdef 0
$ echo `cat tt`
abcdef 7

No idea how reliable this is, but you can use ftell on stdout:

long int start = ftell(stdout);
printf("abcdef\n");
printf("%ld\n", ftell(stdout) - start); // >> 7

EDIT
Checked this on Ubuntu Precise: it does not work if the output goes to the console, but does work if it is redirected to a file.

$ ./a.out 
abcdef
0
$ ./a.out >tt
$ cat tt
abcdef
7
$ echo `./a.out`
abcdef 0
$ echo `cat tt`
abcdef 7
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文