2014-01-26 51 views
0

我写的东西像Java,和我有指针的问题( - - ) 我有一个结构:C++不可能的指针行为

struct _lnHeader32 
{ unsigned char signature[2]; //LN 
    unsigned char architecture; 
    unsigned int length; //Without _lnHeader 
    unsigned int lnHeaderLength; 
    unsigned char permissions; 
    unsigned char typeOfExecutable; 
    unsigned int flowSegment; 
    unsigned int dataSegment; 
    unsigned int loaderSegment; 
    unsigned int cleanerSegment; 
    unsigned int errorSegment; 
    unsigned int exportTable; 
    unsigned int importTable; 
    unsigned int authenticationTable; //Encrypt it with GPG. 
    unsigned int loaderTable; 
}; 

我打开可执行文件,它是在小尾数,由使用std :: fstream的:

lnFile.open(argv[1], std::fstream::in | std::fstream::binary); 
if (false == lnFile.is_open()) 
throw (unableToOpen); 
lnSize = getFileSize(lnFile); 
lnImage = new (std::nothrow) unsigned char [lnSize]; 
if (0 == lnImage) 
throw (noMem); 
lnFile.read(reinterpret_cast<char*>(lnImage), lnSize); //#1 Possible mistake? 
if (!lnFile) 
throw (unableToRead); 
lnFile.close(); 

然后我点_lnHeader32 *来分配lnImage:

lnHeader32 = reinterpret_cast<_lnHeader32*>(lnImage); 

在最后我通过两种方法打印整个结构:

//Method 1 
std::cout << reinterpret_cast<unsigned int*>(lnImage) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+2) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+3) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+7) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+11) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(lnImage+12) << "\n\n"; 

//Method 2  
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->signature) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->architecture) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->length) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->lnHeaderLength) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->permissions) << "\n"; 
std::cout << reinterpret_cast<unsigned int*>(&lnHeader32->typeOfExecutable) 
                    << "\n\n"; 

它给了我像输出:

0xe8b260 
0xe8b262 
0xe8b263 <--- 
0xe8b267 
0xe8b26b 
0xe8b26c 

0xe8b260 
0xe8b262 
0xe8b264 <--- Should be 0xe8b263 | Here starts problem 
0xe8b268 
0xe8b26c 
0xe8b26d 

它通过使用第一种方法打印以及lnHeader32的领域,但我更喜欢使用第二种方法。我计算了一切几次。为什么会发生? 可执行文件是由perl编译器生成的,对它有什么影响?

+5

https://en.wikipedia.org/wiki/Data_padding –

+0

使用nothrow new,只检查结果为null,然后抛出是一个真正的WTF? –

+0

现在一切都很好。谢谢你,Oli Charlesworth。 – SysOp

回答

3

由于填充(见https://en.wikipedia.org/wiki/Data_padding),你的结构实际上是这样的:

struct _lnHeader32 { 
    unsigned char signature[2]; //LN 
    unsigned char architecture; 
    unsigned char PADDING[1];//so next member will be aligned by 4 
    unsigned int length; //Without _lnHeader 
    unsigned int lnHeaderLength; 
    unsigned char permissions; 
    unsigned char typeOfExecutable; 
    unsigned char PADDING[2];//so next member will be aligned by 4 
    unsigned int flowSegment; 
    unsigned int dataSegment; 
    unsigned int loaderSegment; 
    unsigned int cleanerSegment; 
    unsigned int errorSegment; 
    unsigned int exportTable; 
    unsigned int importTable; 
    unsigned int authenticationTable; //Encrypt it with GPG. 
    unsigned int loaderTable; 
}; 
1

的C字段++内存类型是没有必要的连续,有一定的规则,当编译器领域之间引入填充控制。

不同类型的字段通常对齐在预先确定的边界。在这种情况下, char具有1个字节的大小,并且它是1对齐的,int具有4个字节的大小并且它是4对齐的。 (你可以找到更多关于这个here的细节)。

所以,你的结构是要像这样在内存

0: signature[0] 
1: signature[1] 
2: architecture 
3: PADDING! 
4: first byte of length 
... 

而你得到的,因为填充的长度字段中的值不正确。

我建议你不要将原始数据读入内存,并重新将其解释为某种类型。这可能是非常危险的,因为你很难确定你的编译器如何将你的类型与内存对齐。

一个更为安全的解决方案是创建一个辅助功能,如

_lnHeader32 readLnHeader32(const char* binary); 

,并在此功能由一个从文件中读取二进制流中读取的_lnHeader32结构一个领域。