c++ - 这个从 long in a union 到 char* 和 back 的转换是做什么的?

标签 c++ windows winapi type-conversion

当我偶然发现这段代码时,我正在检查一个简单的可执行打包程序的代码,该打包程序将一个部分写入可执行文件中,并在启动期间将其解压缩:

void setDistance( unsigned long size )
{
    char* set = (((char *)I)+pUnpacker->VirtualAddress);
    union
    {
        short sh[2];
        long  l;
    } conv;
    conv.l      = size;
    conv.sh[0]  = 0;

    unpacker_set(set, (char *)(&conv.l), 4, TEXT_DISTANCE);
}

Size 是从内存中的解包程序代码到应该被解包的 Section 开头的距离。在加载程序代码中,它被定义为无符号长整型。 另一方面,unpacker_set 有这段代码:

void inline unpacker_set( char* at, char* what, size_t size, unsigned long sig )
{
    DWORD oldprotect;
    unsigned char *set  = (unsigned char *)at;

    while(*((unsigned long*)(set)) != sig)
        set++;

    if(VirtualProtect(set, size, PAGE_READWRITE, &oldprotect) == TRUE)
        for(unsigned i=0; i<size; i++)
            *(set+i) = *(what+i);
}

虽然我知道第二个例程替换了解包程序代码中的值,但我想知道为什么要解决 union 的麻烦。任何帮助将不胜感激。

最佳答案

可能理解代码的最好方法是编写一个非常简单的测试用例并查看它的作用:

#include <iostream>

void f()
{
  union 
  {
    short sh[2];
    long l ;
  } conv ;
   conv.l = 100000000 ;

   std::cout << std::hex << conv.l << std::endl ;

  conv.sh[0] = 0 ;

  std::cout << std::hex << conv.l << std::endl ;
}

int main()
{
  f() ;
}

我看到的输出如下:

5f5e100
5f50000

所以代码意图看起来像是在试图屏蔽掉大小的高阶位,尽管这非常丑陋并且不太可能是可移植的。

正如大卫指出的那样,您应该注意 strict aliasing .本文Type-punning and strict-aliasing甚至更好,因为它有一些使用 union 的现实世界问题的可靠示例。因此,为了确保此代码在假设 gccclang 的情况下按预期工作,您需要传入以下命令行参数 -fno-strict-aliasing.

关于c++ - 这个从 long in a union 到 char* 和 back 的转换是做什么的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15743788/

相关文章:

c++ - 这是将循环锁定为每秒 60 个循环的好方法吗?

python - ctypes MessageBoxW 返回意外的中文字符

windows - Directshow 支持的容器格式

winapi - 使用 CryptUIWizDigitalSign API 签署 appxbundle

c++ - 如何使用替代数据流添加新文件属性

c++ - std::unique_ptr 作为在 std::thread 中运行的参数

c++ - 删除由函数创建的数组

用于复制文件 : : confused about relative address (tilde) 的 C++ 代码

windows - Wireshark 过滤器语法

c++ - 动态调整组合框的宽度,以便显示整个字符串