c# - BitConverter 的 C++ 等价物

标签 c# c++ arrays c++11 bitconverter

我正在尝试读取文件的 PE header 以获取一些信息。对于 .NETC#,我使用 BitConverter 将读取文件后获得的字节数组转换为等效的整数。我希望对 C++ 做同样的事情,但不确定最佳方法。我正在使用 unsigned char array 作为 Byte array 等价物。

代码如下..

uint16_t GetAppCompiledMachineType(string fileName)
{
    const int ptr_offset = 4096;            
    const int mac_offset = 4;
     char *data = new char[4096];
    fstream f;
    f.open(fileName, ios::in | ios::binary  );
    f.read(data, 4096);


    int32_t pe_addr= *reinterpret_cast<int32_t*>(data, ptr_offset);
    uint16_t machineUint = *reinterpret_cast<std::uint16_t*>(data, pe_addr + mac_offset);
    return machineUint;

 }
int _tmain(int argc, _TCHAR* argv[])
{

      string fileName = "<some_path>\\depends.exe";
      uint16_t tempInt = GetAppCompiledMachineType(fileName);
      cout<<tempInt;
      std::getchar();

    return 0;
}

我将使用 O/P 查询 PE header 以获取信息。这里需要相当于 BitCOnverter 的东西。希望它能奏效。

更新:感谢您的回复。正如建议的那样,我正在尝试使用强制转换,将 字符数组 转换为 Int,以读取 PE Header,但它给了我访问冲突未处理的异常。这是完整的代码,文件有效并且正在读取。我尝试了调试并禁用了优化,但无济于事。

请指教。

非常感谢。

最佳答案

你有一个字节数组指针(char* data)然后简单地将指针移动到你需要的偏移量data + PE_POINTER_OFFSET , 转换为指向整数的指针 (int*)(data + PE_POINTER_OFFSET)并尊重指针以获取值(value):

int32_t head_addr = *reinterpret_cast<int32_t*>(data + PE_POINTER_OFFSET);
uint16_t machineUint = *reinterpret_cast<uint16_t*>(data + head_addr + macoffset);

编辑 1:您正在尝试阅读 PE,所以我可以安全地假设您的环境是 Windows。 x86 和 x64 都支持未对齐的内存访问(当然你会为此付出性能代价,但你可能不会注意到任何东西,你会节省 memcpy 秒)。

Itanimum(如果您必须支持它)和(非常老的)ARM 可能是个问题:对于第一个,只需使用 __unaligned对于您的 char 数组和第二个(如果您不让编译器为您完成这项工作),您可以使用 __packed .

另请注意,此假设(加上字节顺序)是有效的,因为您在 Windows 环境中使用 PE 文件,如果您必须编写可移植代码或阅读其他内容,那么这不是正确的方法(在简而言之,您必须处理单个字节并使用固定顺序复制它们)。

编辑 2:根据您使用的更新代码,问题出在 *reinterpret_cast<int32_t*>(data, ptr_offset) 上,请注意,您没有将指针与偏移量相加,并且偏移量无效(它应该是 60 - 如果我没记错的话)。你在那里做的是从地址为 4096 的绝对位置读取,这会导致访问冲突。在代码中:

uint16_t GetAppCompiledMachineType(string fileName)
{
    const int32_t PE_POINTER_OFFSET = 60;            
    const int32_t MACHINE_OFFSET = 4;

    char data[4096];

    fstream f;
    f.open(fileName, ios::in | ios::binary);
    f.read(data, sizeof(data));

    int32_t pe_header_offset = *reinterpret_cast<int32_t*>(
        data + PE_POINTER_OFFSET);

    // assert(pe_header_offset + MACHINE_OFFSET < sizeof(data));

    return *reinterpret_cast<std::uint16_t*>(
        data + pe_header_offset + MACHINE_OFFSET);
}

此代码仍远未达到生产质量,但请注意一些更改:

  • 缓冲区 data不是动态分配的,那么您不需要释放该内存(您没有释放分配的内存,Windows 会在进程退出时为您释放它,但如果您多次调用该函数,您将消耗内存)。
  • 对于静态分配的数组,您可以使用 sizeof()确定缓冲区大小(作为 read() 的输入)。
  • PE_POINTER_OFFSET现在具有正确的值(60 而不是 4096)。
  • 偏移自 data现在可以正确计算(作为 dataPE_POINTER_OFFSET 的总和)。

所有这些都表明我们仍在使用缓冲方法,但它在这里毫无用处,因为fstream将为我们管理。让我们简化我们的代码(副作用也让它更健壮,我们不假设 PE header 适合我们的 4K 缓冲区)。

uint16_t GetAppCompiledMachineType(string fileName)
{
    const int32_t PE_POINTER_OFFSET = 60;            
    const int32_t MACHINE_OFFSET = 4;

    fstream f(fileName, ios::in | ios::binary);

    int32_t pe_header_offset:
    f.seekg(PE_POINTER_OFFSET); f >> pe_header_offset;

    uint16_t machineType;
    f.seekg(pe_header_offset + MACHINE_OFFSET); f >> machineType;

    return machineType;
}

现在无需强制转换和转换即可工作(但仍假设 PE 和机器字节顺序匹配)。

关于c# - BitConverter 的 C++ 等价物,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26255229/

相关文章:

C++ Builder/Winapi 不同的加载/进度条类型

c - 试图让 scanf 不去 for 循环中的新行(C 编程)

php - 插入一个包含多个值的数组,其中一些值本身就是一个数组到数据库

Java字符串数组初始化循环结构内外

c# - 最大化自己的窗口不会覆盖整个屏幕

C# 类和对象 : Object contains a single vaue

C# 防止在不使用 Enabled=false 的情况下点击表单

Java Base64.getDecoder().decode() C# 等效项

c++ 调用 delete[] 导致崩溃

可以附加到正在运行的进程的 C++ 探查器?