【问题标题】:How to capture output of C++ function printf()如何捕获 C++ 函数 printf() 的输出
【发布时间】:2017-06-27 00:36:02
【问题描述】:

我以前做过,但已经有一段时间了,我在查找任何相关示例时遇到了问题。我有这个遗留代码:

namespace LegacyUtil {    
    public ref class Calc
    {
    public:
        static int Combos(int s)
        {
            int t = 0;
            // bunch of irrelevant loops
            printf("%c%d %c%d D%d\n", m, b, a, d, z);
            t++;
            return t;
        }
    };
}

注意:如果需要,我可以在 Visual C++ 中编辑/重新编译它,但我必须至少跳过一圈。

我的问题:如何从我的 C# 代码中捕获对 printf() 的 C++ 调用的输出?我有这个代码:

int test = LegacyUtil.Calc.Combos(1040);

执行成功,但我只得到返回的整数,我想要字符串输出。请帮忙!

【问题讨论】:

  • 你试过了吗:std::stringstreamsnprintf
  • @ThomasMatthews 根本没有尝试修改遗留代码,并希望无需修改此代码即可捕获输出
  • 您要返回Combos 中的哪些值?
  • @EvanWeissburg 你看到对 printf() 的调用了吗?当前输出一个长度为 11 个字符的字符串,末尾有一个换行符。它在一个循环中执行了数百次,我需要 C# 才能访问该字符串
  • 可以用 fprinf 代替 printf 吗?因为 fprintf 会将输出重定向到一个文件,所以您可以读取该文件以获取输出。

标签: c# c++ printf


【解决方案1】:

printf 的输出转到stdout,这是一个 C 文件流(或 FILE*)。您基本上需要将 C++ 代码的标准输出映射到与 C# 兼容的流。

This answer to another question should help you do that.

要将您的 C++ 流重定向到您的 C# 控制台输出,您可以尝试(参见:Redirecting Console.Out):

// courtesy of Reed Copsey
[DllImport("Kernel32.dll", SetLastError = true) ]
public static extern int SetStdHandle(int device, IntPtr handle);
...
consoleStream = new FileStream(Console.OpenStandardOutput());
SetStdHandle(-11, consoleStream.handle);

(注意:我根本没有测试这个)

【讨论】:

  • 现在我们开始讨论了!谢谢,我会回来的
  • 我尝试了 Reed 的解决方案,但不幸的是它不起作用。它不会引发任何错误,但我生成的 .txt 文件是空的(是的,我确保刷新并关闭流)。我认为他的解决方案旨在捕获 c# 控制台应用程序的输出
【解决方案2】:

如果您决定不更改原始源代码,您可以修改(我很乐意这样称呼它)您自己的代码到 printf 的位置。但请谨慎行事,并预测问题。

printf 是一个库调用。如果您编写自己的 printf,并确保它在链接顺序中系统库之前,您的版本将优先于系统库被调用。

另外,#define 系统 printf 给你自己的可能就足够了:所以

#define printf my_print_func

虽然这种文本替换很容易出错,而且会出现其他不简单的 printf 调用(例如 sprintfsnprintf 或原始中定义的其他函数)代码)

【讨论】:

  • 不是 100% 反对改变它,它 可以做到的,但我一辈子都不记得如何在 C++ 中处理字符串以及这个长度函数的输出变化很大
  • 如果我必须更改源代码,我会改成什么?我想我可以尝试让 sprintf() 与 char 缓冲区一起工作,但我终其一生都不记得如何将其返回到 C#。
  • 我曾经通过两次调用我编写的 C 样式包装函数来完成此操作,该函数接受一个字节数组并返回它写入的任何内容的长度,但如果输入则实际上不会写入任何内容缓冲区为空。所以第一次调用会得到长度(在这种情况下你可以用 printf 得到,因为它返回写入的长度),然后在再次调用写入它的编组 C 样式包装器之前设置 C# 字节数组的大小。
【解决方案3】:

就我的理解而言,基本上你希望一个程序的输出被另一个程序捕获。

使用以下命令创建可执行文件:

#include <stdio.h>

int main()
{
   char line[BUFSIZ];
   while ( fgets(line, BUFSIZ, stdin) != NULL )
   {
      /* Do something with the line of text
   }
}

然后你可以将任何程序的输出通过管道传递给它,逐行读取内容,对每一行文本做一些事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 2013-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多