从union中的long类型强制转换为char*类型,然后再返回,会做什么?

What does this cast from long in a union to char* and back do?

本文关键字:类型 然后 返回 什么 char long 中的 union 转换      更新时间:2023-10-16

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

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开头的距离。在加载器代码中,它被定义为unsigned long。另一方面,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);
}

虽然我理解第二个例程替换了来自解包程序代码的值,但我想知道为什么使用联合的麻烦是完成的。

理解代码的最好方法可能是编写一个非常小的测试用例,看看它做了什么:

#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

因此,代码意图看起来像是试图掩盖大小的高阶位,尽管这是非常丑陋的,它不太可能是可移植的。

正如David指出的,你应该意识到严格的混叠。这篇类型双关语和严格混叠的文章甚至更好,因为它有一些使用union的真实世界问题的可靠示例。因此,为了确保此代码按预期工作,假设gccclang,您需要传入以下命令行参数-fno-strict-aliasing

相关文章: