【问题标题】:Having trouble getting the output of Linux 'dd' command in C++ program在 C++ 程序中获取 Linux 'dd' 命令的输出时遇到问题
【发布时间】:2017-04-04 09:53:37
【问题描述】:

我正在尝试使用sudo dd if=/dev/sda ibs=1 count=64 skip=446 命令从主引导记录中获取分区表信息以对其进行解析我基本上是在尝试将输出读取为字符串以进行解析,但是所有我得到的是以下内容:� !。我期待的是:

80 01 01 00 83 FE 3F 01 3F 00 00 00 43 7D 00 00 00 00 01 02 83 FE 3F 0D 82 7D 00 00 0C F1 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

我当前的代码如下所示,取自这里:How to execute a command and get output of command within C++ using POSIX?

#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <string>

using namespace std;

string exec(const char* cmd) {
    char buffer[128];
    string result = "";
    FILE* pipe = popen(cmd, "r");
    if (!pipe) throw std::runtime_error("popen() failed!");
    try {
        while (!feof(pipe)) {
            if (fgets(buffer, 128, pipe) != NULL)
                result += buffer;
        }
    } catch (...) {
        pclose(pipe);
        throw;
    }
    pclose(pipe);
    return result;
}

int main() {

    string s = exec("sudo dd if=/dev/sda ibs=1 count=64 skip=446");
    cout << s;

}

显然我做错了什么,但我无法找出问题所在。如何将正确的输出输入到我的字符串中?

【问题讨论】:

  • 顺便说一句,你应该阅读Why is “while ( !feof (file) )” always wrong?
  • 如果你从命令行运行命令,输出会是你所期望的吗?我严重怀疑它,因为该命令只会转储原始二进制数据。并且无法像文本一样处理原始二进制数据。
  • 另外,你为什么将阅读循环放在try-catch 中?唯一可能导致异常的是,如果您在附加到字符串时内存不足。即便如此,程序终止还是会关闭管道,因此实际上没有必要。
  • 啊,谢谢。我添加了| hexdump -C,现在可以正常使用了
  • 你为什么还要在外部进程中运行dd?你可以随便open("/dev/sda"...)seek(446)read(64...)

标签: c++ exec dd


【解决方案1】:
while (!feof(pipe)) {

这是your first bug

result += buffer;

这是您的第二个错误。 buffer 是一个 char 数组,在此上下文中衰减为 char *。如您所知,字符串上下文中的 char * 通常被解释为以“\0”字节结尾的 C 风格字符串。

您可能已经注意到,您希望读取大量 00 字节。好吧,在char 数组衰减到char * 之后,直到第一个00 字节的所有内容都将附加到您的result,而不是128 个字节。如果这 128 个字节中没有 00 字节,您最终可能会得到一些随机垃圾,作为额外的奖励,崩溃的可能性很小。

if (fgets(buffer, 128, pipe) != NULL)

这是您的第三个错误。如果读取的数据恰好包含一个0A 字节,一个'\n' 字符,则不会读取128 个字节。

cout << s;

这是您的第四个错误。由于数据(在修复了所有其他错误之后)可能包含二进制内容,因此您的终端不太可能成功显示各种字节,尤其是字节 001F

要修复您的代码,您需要:

  1. 正确处理文件结束条件。

  2. 正确读取二进制数据。 fgets() 等人完全不适合这项任务。如果你坚持使用 C 文件结构,你唯一合理的选择是使用fread()

  3. 从二进制数据块中正确地组装 std::string。仅仅在它上面附加一个char 缓冲区,交叉手指,并希望最好,是行不通的。您很可能需要使用两个参数的 std::string 构造函数,它将一个开始和一个结束迭代器值作为参数。

  4. 正确显示二进制数据,而不是像这样将整个 blob 转储到 std::cout。最常见的方法是std::hex 操纵器,并将每个char 勤奋上转换为int作为无符号值

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-25
    • 2021-01-25
    • 2018-12-23
    • 2023-04-05
    • 2017-04-07
    • 2010-09-18
    • 1970-01-01
    • 2013-08-06
    相关资源
    最近更新 更多