使用二进制数据和无符号字符

时间:2018-07-31 23:42:30

标签: c++ c

我正在编写一个程序,该程序读取二进制文件(特别是Windows PE文件Wikipedia pagedetailed PE structure)的内容。
由于文件中存在二进制数据,因此这些字符通常会“落在” ASCII范围(0-127)之内,并导致出现负值。

为确保我不会使用不必要的负值,我可以传递const unsigned char *或将计算中的结果字符转换为unsigned char

一方面,传递const unsigned char *很有意义,因为数据是非数字的,具有数值,因此应将其视为正数。
另外,它可以让我执行计算而无需将结果强制转换为unsigned char
另一方面,如果不先将常量字符串强制转换为{{1},就不能将常量字符串(const char *,例如预定义字符串“ MZ”,“ PE \ 0 \ 0”等)传递给函数。 }。

在这种情况下,什么是更好的方法或最佳实践?

1 个答案:

答案 0 :(得分:2)

我认为我会使用unsigned char,但要避免进行强制转换,而是定义一个名为ustring的小类(或类似的东西)。您有两个选择。一种是在std::basic_string上实例化unsigned char。这可能很有用(它为您提供了std::string的所有功能,但使用了unsigned char而不是char。明显的缺点是它可能过大了,并且基本上没有兼容性std::string,即使它几乎是完全一样的东西。

另一个明显的可能性是定义自己的类。由于您显然主要关心字符串文字,因此我可能会采用这种方式。该类将以字符串文字形式初始化,并且只保存指向该字符串的指针,但以unsigned char *而不是char *开头。

然后还有一个步骤来使生活变得更好:定义一个用户定义的文字运算符,其名称类似_us,因此从字符串文字中创建您类型的对象将类似于以下内容:auto DOS_sig = "MZ"_us;

class ustring {
    unsigned char const *data;
    unsigned long long len;
public:
    ustring(unsigned char const *s, unsigned long long len) 
        : data(s)
        , len(len)
    {}

    operator char const *() const { return data; }

    bool operator==(ustring const &other) const {
        // note: memcmp treats what you pass it as unsigned chars.
        return len == other.len && 0 == memcmp(data, other.data, len);
    }

    // you probably want to add more stuff here.
};

ustring operator"" _us(char const * const s, unsigned long long len) {
    return ustring((unsigned char const *)s, len);
}

如果我没记错的话,这应该很容易使用。例如,假设您已经对您认为是PE文件的内存进行了映射,其基址为mapped_file。要查看它是否具有DOS签名,您可以执行以下操作:

if (ustring(&mapped_file[0], 2) == "MZ"_us)
    std::cerr << "File appears to be an executable.\n";
else
    std::cerr << "file does not appear to be an executable.\n";

警告:我还没有对此进行测试,因此击剑杆错误和类似错误很可能发生-例如,我不记得传递给用户定义的文字运算符的长度是否包含NUL终止符。这并不是要表示完成的代码,而只是概述可能有助于探索的一般方向的草图。