当我偶然发现这段代码时,我正在检查一个简单的可执行打包程序的代码,该打包程序将一个部分写入可执行文件中,并在启动期间将其解压缩:
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
的现实世界问题的可靠示例。因此,为了确保此代码在假设 gcc
或 clang
的情况下按预期工作,您需要传入以下命令行参数 -fno-strict-aliasing
.
关于c++ - 这个从 long in a union 到 char* 和 back 的转换是做什么的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15743788/